懒惰的正则表达式在C#中未按预期工作

3
我有以下正则表达式:a?\W*?b,和一个字符串,.! ,b
在查找匹配时,我得到的是,.! ,b,而不是我期望的b。为什么会这样?如何修改正则表达式以获得我需要的结果?
谢谢您的帮助。

请提供一些您想匹配和不想匹配的示例。最好不要将您的正则表达式简化太多(下面的评论建议您实际上正在做其他事情),否则解决方案可能会变得过于简单。 - Tim Pietzcker
7个回答

4

在这里,懒惰量词对你想要的并没有帮助。让我们看看发生了什么。

正则表达式引擎从字符串的开头开始。首先尝试匹配a。它无法匹配,但这不是问题,因为a是可选的。

然后,有一个懒惰的\W*?,所以正则表达式引擎跳过它,但记住当前位置。

接下来,它尝试匹配b。它无法匹配,所以它回溯并成功地使用\W*?匹配,。然后它继续尝试匹配b(因为是懒惰量词)。它仍然不能匹配,并且回溯。这反复几次,直到最后正则表达式引擎到达b。现在匹配完成-正则表达式引擎宣布成功。

所以正则表达式按照规定工作-只是意图不同。现在的问题是:你到底想让正则表达式做什么?

例如,如果你真正想要的是:

匹配单独的b,除非它前面有a和一些非单词字符,在这种情况下匹配从ab的所有内容,然后使用

b|a\W*b

如果我有以下正则表达式'a?\W*?b?\W*?c?\W*?d?',并且我希望任何非空匹配都以字母开头和字母结尾,该怎么办? - StuffHappens
一个可以实现你刚才所写的正则表达式是 ^([a-z].*[a-z]$|)$。匹配以字母开头和结尾的字符串,或者匹配空字符串。如果你想要大写字母也能匹配,可以使用 RegexOptions.IgnoreCase。如果你还想允许非ASCII字母,可以使用 \p{L} 代替 [a-z] - Tim Pietzcker
+1,非常好的解释...我今天学到了一些关于正则表达式的东西 :) - Thomas Levesque

1

一个惰性表达式只从右侧惰性,即通过删除右侧字符尽可能缩短长度,但不会删除左侧字符。

为了使匹配开始更晚,您需要在它之前使用贪婪表达式来吞噬您不想匹配的字符。

或者,正如Tim所示,如果第一个字符存在,您可以仅匹配第一个字符和以下分隔符以使匹配开始更晚。


0
例如,以下内容可能有效:(a\W*)?b 为了更好地了解可能解决您的问题的方法,您应该包含更多示例。

实际上,原始的正则表达式是'a?\W*?b?\W*?c?',我希望任何匹配都不包含非字母(\W)符号,无论是从开头还是结尾。 - StuffHappens
你能否澄清一下这个问题(比如提供一些例子)并将其放在原始问题中,而不是放在评论区中,这样更难找到? - Tim Pietzcker

0

你的正则表达式与整个字符串匹配如下:

  1. a,零或一次重复(在这种情况下为“”)
  2. 任何非字母数字字符,重复次数不限,尽可能少(在这种情况下为“,。!,”)
  3. b

在你的情况下,正则表达式与整个字符串匹配,因此它将不能只找到 b (它不会找到相同部分的多个匹配)。

如果在像',。!,db'这样的字符串中搜索,它将找到 b。


我可以看出你正在使用Expresso,我的屏幕上也有完全相同的描述 ;) - Thomas Levesque
是的 - 我认为这是一个很好的描述,所以我没有费心重新写 :-) - Tor Livar

0

a? 表示 "我想要零个或一个实例的a" - 这得到满足,因为没有实例,接着

\W* 表示 "我想要零个或更多的非单词字符",这得到满足,因为有标点符号和空格字符,最后

b 表示 "匹配字母b",它得到了满足。所以您整个字符串都符合正则表达式。

如果在任何人建议可能的解决方案之前您可以提供更多可能输入的示例,那将会有所帮助。


你的解释忽略了懒惰量词 *?... 为什么它在这里不起作用? - Thomas Levesque
\W*? 是懒惰模式。因此,它应该包含尽可能少的符号。这里最少的符号数量是0。 - StuffHappens

0

你的例子没有说明为什么a?是你正则表达式的一部分,但如果要在看起来像,.! ,b的字符串中只匹配b,你可以使用向后查找,像这样:(?=\W*?)b

这个正则表达式匹配的是在一个字符之前有零到多个“非单词字符”(尽可能少)的b

如果你只想在类似a,.! ,b的字符串中匹配ab,你需要使用捕获组: (a?)\W*?(b),其中第一个捕获组将保存可能存在的a,第二个捕获组保存b


0

把一个正则表达式称为贪婪或非贪婪是错误的。你可以在整个正则表达式中使用非贪婪量词,但它仍然会尝试在最早的机会开始匹配,就像你发现的那样。同样,只使用贪婪量词的正则表达式不能保证返回最长的匹配。例如,

Regex.Match("foo bar", @"\w+ (?:b|bar)")

......返回foo b,因为交替选择了第一个可行的替代项,即使后面有更长的匹配结果。(请注意,我在谈论像.NET这样派生自Perl的正则表达式语法;某些语法,如awkegrep,确实坚持最长可能的匹配。但是,由于这些语法没有非贪婪量词,贪婪模式不仅是默认模式,而且是唯一的模式。)

简而言之,不存在贪婪或非贪婪的正则表达式,只有贪婪或非贪婪的量词。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接