首页 > 解决方案 > 不能使非贪婪匹配工作

问题描述

在 Python3.4 中,我使用了 re 库(正则表达式库给出了相同的结果),并且得到了我不期望的结果。

我有一个字符串 s = 'abc'。我期望以下正则表达式:

re.match(r"^(.*?)(b?)(.*?)$", s).groups()

..匹配三个非空组,即:

('a', 'b', 'c')

--因为模式的中间部分是贪婪的(b?)。相反,只有最后一组是非空的:

('', '', 'abc')

我得到以下两个相同的结果:

re.match(r"^(.*?)(b?)(.*?)$", s).groups()   #overt ^ and #
re.fullmatch("(.*?)(b?)(.*?)", s).groups()  #fullmatch()

如果我使第一组成为贪婪匹配,那么结果是:

('abc', '', '')

我想我会预料到的,因为贪婪.*的人在其他群体看到它之前就已经消耗了整个字符串。

我正在尝试构建的正则表达式当然比这更复杂,否则,我可以b从左右组中排除:

re.match(r"^([^b]*?)(b?)([^b]*?)$", s).groups()

但在我的实际用例中,中间组是一个长几个字符的字符串,其中任何一个都可能单独出现在左组或右组中,所以我不能只从左组或右组中排除这些字符。

我查看了标记为的其他问题,但似乎没有人回答这个问题,尽管我怀疑 ctwheels 在python 非贪婪匹配中的回复是我的问题的原因(前两组的可选性阻止了正则表达式引擎从实际失败直到它到达字符串的末尾,然后它只需要回溯一些方法来获得非失败匹配)。

标签: regexpython-3.xregex-greedy

解决方案


我希望以下正则表达式

re.match(r"^(.*?)(b?)(.*?)$", s).groups()

匹配三个非空组..因为模式的中间部分是贪婪的

不,你不应该期待。实际上,出于以下原因,这种行为是非常值得期待的:

您特别指示第一组中的正则表达式是惰性的,这意味着它将接受尽可能少的字符(在这种情况下为零),因为没有其他东西迫使它寻找更多。因此,虽然第二组中的正则表达式是贪心的(即b?),但它仍然无法匹配,b因为位置仍为 0。

您可以通过替换您的第二组来确认这一点(.?)在这种情况下将匹配a而不是b您可能期望的那样。这^(.*?)(.?)(.*?)$. _

现在,如果您的规则不允许不存在b,您可以轻松地将您的正则表达式更改为,但是由于您希望第一组存在但同时^(.*?)(b)(.*?)$继续匹配,因此允许不存在(即,第二组实际上可以是空的),那么这个解决方案并不能解决问题。b b

目前我想到的满足这两个条件的唯一解决方案是使用Lookahead来确定是否b存在。这是一个例子:

^((?:.*?(?=b))|.*?)(b?)(.*?)$

在线尝试

这将继续匹配任何字符(使用.),直到找到b然后停止,否则(即,如果没有b),只要找到尽可能少的字符(这是原始行为),它将停止匹配。换句话说,只要b存在,它将保证第二组不为空。

如果这不符合您的任何条件,请告诉我。


推荐阅读