有人可以解释这些正则表达式的结果

时间:2015-05-09 23:15:53

标签: regex

我正在测试一些随机正则表达式并且遇到了一些奇怪的结果。假设我们有正则表达式(ab|(ba)*|a)*它与aba不匹配,但如果我删除内部星标(ab|(ba)|a)*或者如果我切换术语的顺序,(a|ab|(ba)*)*这两个案例现在匹配aba。那么为什么会这样呢?是否与歧义或嵌套*有关?我知道它是一个奇怪的测试用例,而内部*是多余的,但我只想了解这些结果。我正在使用regex101.com进行测试。

2 个答案:

答案 0 :(得分:3)

交替运算符(|)正在短路,并且将始终尝试匹配最左侧的子模式,直到该模式失败,此时它将尝试匹配下一个子模式。只能匹配非重叠的模式。空字符串匹配导致当前贪婪模式结束,因为空字符串可以无限匹配,并且继续这样做是不合理的,贪婪或不贪婪。贪婪并不一定意味着愚蠢。 :)

因此,对于模式(ab|(ba)*|a)*和字符串'aba',它将匹配字符串开头的“ab”。由于您在最外面的捕获组*上使用贪心量词,因此正则表达式将继续尝试与最外面的捕获组进行更长时间的匹配。匹配迭代器将在第3个字符处,它将尝试匹配'ab',但它将失败。然后,一旦意识到它可能与空字符串无限次匹配(ba)*,它将结束匹配(不使用(ba)* 捕获任何内容而不尝试匹配最后一个替代模式a)并返回最外层重复捕获组的最后一次迭代。

现在,如果你切换与交替运算符链接的子模式的顺序,如(ab|a|(ba)*)*,那将匹配整个字符串,因为匹配器能够使匹配迭代器前进a,然后使用第3个替代子模式的最终空字符串匹配完成匹配。

(ab|(ba)|a)*也有效,因为第二个替代无法与空字符串匹配,因此只要它不匹配ba,它就会成功转到尝试匹配a

修复它的另一种类似方法是使用(ab|(ba)+|a)*。这将正确地导致第二种替代方法正确失败而不是匹配它。

解决此问题的最后一种方法是将锚点用于字符串的末尾,通常由$表示。模式(ab|(ba)*|a)*$能够在匹配第二个替代方案时正确​​失败,因为它意识到它永远不会通过这样做而到达字符串的末尾。它仍将匹配第二个替代最终,但只有在匹配迭代器遍历到字符串结尾之后才会匹配。

这就是为什么您只能从最外面的捕获组中看到一次捕获字符串'aba'的原因。模式(ba)*将始终与索引2-2(或任何空子字符串)匹配,然后结束当前匹配并阻止下一个a匹配,但除非您将捕获任何内容在您的字符串中有一个明确的'ba',它与之前的任何替代品都不重叠。

答案 1 :(得分:2)

您的假设是错误的:它与aba匹配,请参阅here

重点是“正则表达式”更喜欢匹配的区别。但是,如果您强制正则表达式从开始到结束匹配,它将完全匹配aba

更多细节:如果你使用析取模式(例如r|srs其他正则表达式):正则表达式“喜欢”选择左正则表达式{{1在正确的正则表达式r上方。例如,如果正则表达式显示s且输入为(a|aa)*,则可以匹配第一个项目两次,或使用第二个项目。在这种情况下,正则表达式喜欢选择第一个项目两次。

同样适用于重复,正则表达式希望尽可能多地重复 Kleene星 aa中的项目。