即使没有前瞻,添加一些文本如何使此正则表达式与输入匹配?

时间:2018-10-28 22:40:42

标签: python regex pypi-regex

在研究this question的答案时,我想到了这个正则表达式:

(?:(?!\2)(?:,foo=([^,]*),(?=())|.))*\2bar=2

(注意:此正则表达式需要PyPI regex module

(简短说明:正则表达式基于以下事实:先行捕获组在匹配一次后便无法更改其值,因此在找到第一个foo=之后,(?=())匹配并且从那时起(?!\2)将始终失败。)

此正则表达式可与问题中给出的2个示例一起正常使用

>>> pattern = r'(?:(?!\2)(?:,foo=([^,]*),(?=())|.))*\2bar=2'
>>> regex.match(pattern, 'baz=0,foo=1,bar=2,foo=3,bar=4').group(1)
'1'
>>> regex.match(pattern, 'baz=0,foo=1,foo=1,bar=2')
>>>

但是如果在foo=之后出现bar=2 ,会发生一些奇怪的事情:

>>> # this doesn't match, as expected:
>>> regex.match(pattern, 'notfoo=1,bar=2')
>>> # but how the heck does it match this ?!
>>> regex.match(pattern, 'notfoo=1,bar=2,foo=3,')
<regex.Match object; span=(0, 14), match='notfoo=1,bar=2'>

如您所见,字符串'notfoo=1,bar=2,foo=3,'匹配了notfoo=1,bar=2foo=3,甚至不包含在匹配项中,但是如果将其删除,则正则表达式将不再匹配!这怎么可能?这是regex模块中的错误吗?

1 个答案:

答案 0 :(得分:0)

这实际上是很合理的。出现这种情况的原因很简单:回溯。

事件的顺序如下:

  1. 贪婪的团体(?:...)*每次前进一个字符,直到最终在foo=找到,foo=3,的地方
  2. 正则表达式尝试匹配bar=2,但这失败
  3. 正则表达式一次回溯1个字符,直到bar=2匹配为止,从而得到notfoo=1,bar=2的结果。

那么,我们该怎么办?我们可以将bar=2 移到贪婪组中,并使用另一个捕获组来断言正则表达式成功匹配:

(?:(?!\2)(?:,foo=([^,]*),(?=())bar=2()|.))*\3
>>> pattern = r'(?:(?!\2)(?:,foo=([^,]*),(?=())bar=2()|.))*\3'
>>> regex.match(pattern, 'baz=0,foo=1,bar=2,foo=3,bar=4').group(1)
'1'
>>> regex.match(pattern, 'baz=0,foo=1,foo=1,bar=2')
>>> regex.match(pattern, 'notfoo=1,bar=2')
>>> regex.match(pattern, 'notfoo=1,bar=2,foo=3,')
>>>