我正在测试一些随机正则表达式,并发现了一些奇怪的结果。假设我们有正则表达式 (ab|(ba)*|a)*
它与 aba
不匹配,但如果我删除内部星号, (ab| (ba)|a)*
或者如果我切换术语的顺序,(a|ab|(ba)*)*
这两种情况现在匹配 aba
.那么为什么会出现这样的情况呢?这与歧义或嵌套 * 有关吗?我知道这是一个奇怪的测试用例,内部 * 是多余的,但我只想了解这些结果。我使用 regex101.com 进行测试。
最佳答案
交替运算符 (|
) 是短路的,并且将始终尝试匹配最左边的可能子模式,直到该子模式失败,此时它将尝试匹配下一个。只能匹配不重叠的模式。空字符串匹配会导致当前的贪婪模式结束,因为空字符串可以无限匹配,无论贪婪与否,继续这样做是没有意义的。贪婪并不一定意味着愚蠢。 :)
因此,在模式 (ab|(ba)*|a)*
和字符串 'aba'
的情况下,它将匹配来自字符串的开头。由于您在最外层捕获组 * 上使用贪婪量词,因此正则表达式将继续尝试与最外层捕获组进行更长的匹配。匹配迭代器将位于第三个字符,它将尝试匹配“ab”,但会失败。然后,当意识到它可能会与空字符串无限次匹配 (ba)*
时,它将结束匹配(不会捕获 (ba)*
的任何内容) > 和而不尝试匹配最后一个替代模式a
)并返回最外层重复捕获组的最后一次迭代。
现在,如果您切换与 (ab|a|(ba)*)*
等交替运算符链接的子模式的顺序,它将匹配整个字符串,因为匹配器能够使用 a
推进匹配迭代器,然后使用第三个替代子模式的最终空字符串匹配来完成匹配。
(ab|(ba)|a)*
也有效,因为第二个替代不能与空字符串匹配,所以一旦它失败匹配 ba
,它成功地继续尝试匹配 a
。
另一种类似的修复方法是使用(ab|(ba)+|a)*
。这将正确地导致第二个替代方案正确失败,而不是匹配它。
修复此问题的最后一种方法是使用字符串末尾的 anchor ,通常用 $
表示。模式 (ab|(ba)*|a)*$
能够在匹配第二个替代方案时正确失败,因为它意识到这样做永远不会到达字符串的末尾。它最终仍然会匹配第二个替代项,但只有在匹配迭代器遍历到字符串末尾之后。
这就是为什么您在最外层捕获组中只看到一个带有字符串'aba'
的捕获。模式 (ba)*
将始终从索引 2-2(或任何空子字符串)开始匹配,然后结束当前匹配并阻止下一个 a
匹配,但不会捕获任何内容,除非您的字符串中有一个显式的 'ba'
并且不与任何早期的替代项重叠。
关于regex - 有人可以解释这些正则表达式结果吗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30146054/