为什么这个表达式不遵循贪婪的方法?
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();
}
输出:
cool= man! your dog can walk on water dog=
你可以观察到: (狗)组匹配0次。但是,因为,*是贪心,为什么不尝试找到(狗)的最大匹配为1?
任何线索?
答案 0 :(得分:7)
第一个.*
最初匹配整个字符串。然后正则表达式引擎确定是否需要退出以匹配正则表达式的其余部分。但是(?<h>((dog)*))
和(?(h)(?<dog>(.*)))
可以合法地匹配零个字符,因此不需要回溯(就.*
而言)。尝试在该部分使用非贪婪的.*?
。
编辑(回复以下答案中发布的其他信息):好的,将第一个.*
替换为非贪婪的.*?
< / em>有效果,而不是你想要的那个。在“{酷”之后的所有内容之前的所有内容都在小组<cool>
中捕获,现在它正在小组<dog>
中捕获。这是正在发生的事情:
匹配“酷”一词后,(?<cool>(.*?))
最初不匹配(与贪婪行为相反),(?<h>((dog)*))
尝试匹配。这部分将始终成功,无论它在哪里尝试,因为它可以匹配“狗”或空字符串。这意味着(?(h)...)
中的条件表达式将始终评估为true
,因此它会继续并与(?<dog>(.*))
匹配输入的其余部分。
根据我的理解,你想要在命名组<cool>
中的“酷”之后匹配所有内容,除非该字符串包含单词“dog”;然后你想捕获命名组<dog>
中“dog”之后的所有内容。你试图使用conditional,但它不是真正合适的工具。就这样做:
string pattern = @"cool (?<cool>.*?) (dog (?<dog>.*))?$";
这里的关键是最后的$
;它强制非贪婪的.*?
保持匹配,直到它到达字符串的末尾。因为它不贪婪,所以在使用每个字符之前,它会尝试匹配正则表达式的下一部分(dog (?<dog>.*))
。如果有“dog”这个词,那么字符串的其余部分将由(?<dog>.*)
消费;如果没有,正则表达式仍然成功,因为?
使整个部分可选。
答案 1 :(得分:0)
我确实尝试过非贪婪的(.*?)
,但由于非贪婪的(.*?)
代表{0,1}
,因此效果不明显。因为即使零个字符在这里匹配,所以没有效果
任何想法如何纠正它。我的意思是,我想捕获字符串后跟(dog)
如果它存在,否则前一组将捕获字符串(cool(.*))
问题是(dog)
是可选的,如果它存在,我们需要跟随它的字符串。
使用(dog)?
没有任何效果,因为它再次匹配零个字符。
谢谢。