即使没有前瞻性,添加一些文本如何使这个正则表达式匹配输入?
How does adding some text make this regex match the input even though there's no lookahead?
在回答 时,我想到了这个正则表达式:
(?:(?!)(?:,foo=([^,]*),(?=())|.))*bar=2
(注意:此正则表达式需要 PyPI regex
module)
(简短说明:正则表达式依赖于这样一个事实,即前瞻中的捕获组在匹配一次后无法更改其值,因此在找到第一个 foo=
后, (?=())
匹配,从那时起 (?!)
将永远失败。)
此正则表达式可正确处理问题中给出的 2 个示例:
>>> pattern = r'(?:(?!)(?:,foo=([^,]*),(?=())|.))*bar=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=
after a 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=2
的匹配项。 foo=3,
甚至不包含在匹配中,但如果将其删除,正则表达式将不再匹配!这怎么可能?这是 regex
模块中的错误吗?
这实际上很有道理。这种行为的原因很简单:回溯。
事件顺序如下:
- 贪婪组
(?:...)*
一次前进一个字符,直到最终在,foo=3,
处找到foo=
- 正则表达式尝试匹配
bar=2
,但失败了
- 正则表达式一次回溯 1 个字符,直到
bar=2
匹配,得到 notfoo=1,bar=2
. 的结果
那么,我们能做些什么呢?我们可以将 bar=2
移动到 贪婪组并使用另一个捕获组来断言正则表达式匹配成功:
(?:(?!)(?:,foo=([^,]*),(?=())bar=2()|.))*
>>> pattern = r'(?:(?!)(?:,foo=([^,]*),(?=())bar=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')
>>> regex.match(pattern, 'notfoo=1,bar=2')
>>> regex.match(pattern, 'notfoo=1,bar=2,foo=3,')
>>>
在回答
(?:(?!)(?:,foo=([^,]*),(?=())|.))*bar=2
(注意:此正则表达式需要 PyPI regex
module)
(简短说明:正则表达式依赖于这样一个事实,即前瞻中的捕获组在匹配一次后无法更改其值,因此在找到第一个 foo=
后, (?=())
匹配,从那时起 (?!)
将永远失败。)
此正则表达式可正确处理问题中给出的 2 个示例:
>>> pattern = r'(?:(?!)(?:,foo=([^,]*),(?=())|.))*bar=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=
after a 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=2
的匹配项。 foo=3,
甚至不包含在匹配中,但如果将其删除,正则表达式将不再匹配!这怎么可能?这是 regex
模块中的错误吗?
这实际上很有道理。这种行为的原因很简单:回溯。
事件顺序如下:
- 贪婪组
(?:...)*
一次前进一个字符,直到最终在,foo=3,
处找到 - 正则表达式尝试匹配
bar=2
,但失败了 - 正则表达式一次回溯 1 个字符,直到
bar=2
匹配,得到notfoo=1,bar=2
. 的结果
foo=
那么,我们能做些什么呢?我们可以将 bar=2
移动到 贪婪组并使用另一个捕获组来断言正则表达式匹配成功:
(?:(?!)(?:,foo=([^,]*),(?=())bar=2()|.))*
>>> pattern = r'(?:(?!)(?:,foo=([^,]*),(?=())bar=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')
>>> regex.match(pattern, 'notfoo=1,bar=2')
>>> regex.match(pattern, 'notfoo=1,bar=2,foo=3,')
>>>