正则表达式中的“懒惰匹配”和“贪婪匹配”混淆问题

5

我对正则表达式和贪婪与非贪婪模式有些困惑。感觉应该很简单,但好像我漏掉了什么显而易见的东西。

为了让问题更清晰,我把它简化了。请考虑以下字符串和正则表达式模式:

string:
aaxxxb

pattern:
(?<=a)(.*?)(?=b)

result:
axxx

what I expected:
xxx

这个结果是使用 .* 而不是 .*? 的预期结果,我错过了什么吗?
显然,如果我使用 a.*?b,那么会得到 aaxxxb。为什么会这样?应该是懒惰匹配(如 .*?)尽可能少地返回字符,对吗?

1
FYI,几天前已经有人问过完全相同的问题了(答案已经给出,但没有标记为被接受,所以不将其标记为重复)。 - Robin
此外,从SO正则表达式FAQ中,您可以看到懒惰模式和贪婪模式之间的区别在此更深入地讨论 - Robin
可能是 贪婪 vs. 勉强 vs. 占有量词 的重复。 - james.garriss
2个回答

7
你忽略了正则表达式引擎从左到右逐个位置进行匹配,并且只要在当前位置找到匹配项,就会成功匹配。
在你的示例中,模式成功的第一个位置是在第二个“a”的位置上。
"懒惰模式"仅对右侧有效。
如果你想要得到"xxx",更好的方法是使用否定字符类[ ^ab ]*而不是.*
注:虽然与主题不完全相关,但有必要知道:在选择的情况下,DFA正则表达式引擎将尝试获取最大的结果,而NFA将给出第一个成功的结果。

2
总是很高兴阅读您的文章。正如您所说,理解“正则表达式引擎从左到右、逐个位置运行”的概念是一个常见的障碍......更令人困惑的是,我们在处理字符串和模式时都是从左到右进行操作。当我们提到从左到右时,希望能够简单地表达这一点。顺便说一句,我知道您已经了解这一点,但.NET有一个从右到左的选项! :) - zx81
@zw81:谢谢!确实,不要忘记世界上有一部分人是从右到左阅读和书写的,而.NET为正则表达式提供了这种可能性。 - Casimir et Hippolyte

2

用户1277327,你的模式中的(?<=a)部分表示“前面有一个'a'”。当正则表达式引擎在字符串aaxxxb上启动时,第一个“a”不满足该回顾断言,但第二个“a”满足。好的,但是引擎可以匹配那个“a”吗?是的,你的.*中的点允许引擎匹配这个“a”。懒惰修饰符?告诉点星号只吃掉必要的字符,直到我们能够匹配接下来的内容。接下来的内容是一个前瞻,断言下一个字符是“b”。所以引擎吃掉了三个x字符。总的匹配结果是axxx。

如果你觉得贪婪/懒惰很困惑,你可能想看看正则表达式贪婪级别。附带的前后查找教程也可能有所帮助。


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