0

この式が貪欲なアプローチに従っていないのはなぜですか?

string input = @"cool  man! your  dog can walk on water ";
string pattern = @"cool (?<cool>(.*))    (?<h>((dog)*)) (?(h)(?<dog>(.*))) ";

MatchCollection matches = Regex.Matches(input, pattern, RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture | RegexOptions.IgnorePatternWhitespace);


foreach (Match match in matches)
{
    Console.WriteLine("cool=" + match.Groups["cool"].Value);
    Console.WriteLine("dog=" + match.Groups["dog"].Value);
    Console.ReadLine();
}

出力:

クール=男!あなたの犬は水の上を歩くことができます
犬=

あなたが観察できるように: (犬) グループは 0 回一致します。

手がかりはありますか?

4

2 に答える 2

7

1 つ目は、最初.*は文字列全体に一致します。次に、正規表現エンジンは、残りの正規表現と一致させるためにバックオフする必要があるかどうかを判断します。しかし(?<h>((dog)*))、 と (?(h)(?<dog>(.*)))はどちらも合法的にゼロ文字に一致するため、バックトラックは必要ありません (.*に関する限り)。.*?その部分で貪欲でないものを使ってみてください。

編集(以下の回答に投稿された追加情報に応じて):.*わかりました。最初のものを貪欲で.*? ないものに置き換えると効果がありますが、必要なものではありません。以前は "cool" という単語の後のすべてが group でキャプチャされていましたが<cool>、現在は group でキャプチャされてい<dog>ます。何が起こっているかは次のとおりです。

「cool」という単語が一致した後、(?<cool>(.*?))最初は何も一致せず (貪欲な動作の反対)、(?<h>((dog)*))一致しようとします。この部分は、「dog」または空の文字列のいずれかに一致する可能性があるため、どこで試行されても常に成功します。つまり、条件式 in(?(h)...)は常に に評価されるtrueため、先に進み、残りの入力を に一致させ(?<dog>(.*))ます。

<cool>私が理解しているように、文字列に「犬」という単語が含まれていない限り、名前付きグループの「クール」の後のすべてに一致させたいと考えています。次に、名前付きグループの「犬」の後のすべてをキャプチャします<dog>そのために条件を使用しようとしていますが、それは実際には適切なツールではありません。これを行うだけです:

string pattern = @"cool (?<cool>.*?) (dog (?<dog>.*))?$";

ここでの鍵$は最後にあります。.*?文字列の最後に到達するまで、非貪欲に一致を維持するように強制します。貪欲ではないため、(dog (?<dog>.*))各文字を消費する前に、正規表現の次の部分である と一致させようとします。「犬」という単語がある場合、残りの文字列は によって消費され(?<dog>.*)ます。?そうでない場合でも、その部分全体がオプションになるため、正規表現は引き続き成功します。

于 2009-12-26T11:20:06.543 に答える
0

私は貪欲ではないことを試しましたが、貪欲でないことは .and の略であるため、(.*?)明らかな効果はありません。ここではゼロ文字でも一致するため、効果はありません。(.*?){0,1}

どのようにそれを修正できるかについてのアイデア.つまり、文字列をキャプチャしたいのに続いて、(dog)そこに存在するか、前のグループが文字列をキャプチャします(cool(.*))

問題は、それ(dog)がオプションであり、存在する場合、それに続く文字列が必要なことです。

using(dog)?は、再びゼロ文字に一致するため、何の効果もありません。

ありがとう 。

于 2009-12-27T16:29:44.253 に答える