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();
}

输出:

酷=男人!你的狗可以在水上行走
狗=

如您所见: (dog) 组匹配 0 次。但是,* 是贪婪的,为什么不尝试找到 (dog) 的最大匹配项,即 1?

有什么线索吗?

4

2 回答 2

7

第一个.*最初匹配整个字符串。然后正则表达式引擎确定是否需要回退以匹配正则表达式的其余部分。但是(?<h>((dog)*))and (?(h)(?<dog>(.*)))都可以合法地匹配零个字符,因此不需要回溯(就.*而言)。尝试在该部分使用非贪婪.*?

编辑(响应下面答案中发布的附加信息):.*好的,用非贪婪替换第一个.*? 确实有效果,只是不是你想要的。以前“cool”这个词后面的都是group<cool>里面的,现在都是group里面的<dog>。这是正在发生的事情:

在匹配“cool”这个词后,(?<cool>(.*?))最初什么都不匹配(与贪婪行为相反),并(?<h>((dog)*))尝试匹配。这部分无论在哪里尝试都会成功,因为它可以匹配“dog”或空字符串。这意味着条件表达式 in(?(h)...)将始终计算为true,因此它会继续并将输入的其余部分与 匹配(?<dog>(.*))

据我了解,您希望匹配命名组中“cool”之后的所有内容<cool>,除非字符串包含单词“dog”;那么你想在命名组中捕获“狗”之后的所有内容<dog>。您正在尝试为此使用条件,但这并不是真正的正确工具。只需这样做:

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

这里的关键是$结尾;它迫使非贪婪.*?者继续匹配,直到到达字符串的末尾。因为它是非贪婪的,所以它会(dog (?<dog>.*))在使用每个字符之前尝试匹配正则表达式的下一部分 , 。如果存在单词“dog”,则字符串的其余部分将被(?<dog>.*);消耗掉。如果不是,则正则表达式仍然成功,因为这?使整个部分成为可选的。

于 2009-12-26T11:20:06.543 回答
0

我确实尝试了非贪婪(.*?),但它没有效果,这很明显,因为非贪婪(.*?)代表 .{0,1}并且因为即使是零个字符也匹配这里,所以没有效果。

任何想法如何纠正它。我的意思是,我想捕获字符串,(dog)如果它存在的话,否则前一组将捕获字符串(cool(.*))

问题是它(dog)是可选的,如果它存在,我们需要它后面的字符串。

using(dog)?没有任何效果,因为它再次匹配零个字符。

谢谢 。

于 2009-12-27T16:29:44.253 回答