【问题标题】:Impossible lookbehind with a backreference使用反向引用不可能向后看
【发布时间】:2012-05-03 23:26:28
【问题描述】:

据我了解

(.)(?<!\1)

永远不应该匹配。实际上,php 的preg_replace 甚至拒绝编译它,ruby 的gsub 也是如此。不过,python re 模块似乎有不同的看法:

import re
test = 'xAAAAAyBBBBz'
print (re.sub(r'(.)(?<!\1)', r'(\g<0>)', test))

结果:

(x)AAAA(A)(y)BBB(B)(z)

谁能为这种行为提供合理的解释?

更新

此行为似乎是 a limitation 模块中的 re。替代的regex 模块似乎可以正确处理断言中的组:

import regex

test = 'xAAAAAyBBBBz'

print (regex.sub(r'(.)(?<!\1)', r'(\g<0>)', test))
## xAAAAAyBBBBz

print (regex.sub(r'(.)(.)(?<!\1)', r'(\g<0>)', test))
## (xA)AAA(Ay)BBB(Bz)

请注意,与pcre 不同,regex 还允许可变宽度的lookbehinds:

print (regex.sub(r'(.)(?<![A-Z]+)', r'(\g<0>)', test))
## (x)AAAAA(y)BBBB(z)

最终,regex 将被包含在标准库中,正如PEP 411 中所述。

【问题讨论】:

  • 匹配就像你使用了(.)(?!\1)

标签: python regex python-3.x python-2.7


【解决方案1】:

这看起来确实像 Python re 模块中的一个限制(说“错误”的好方法,正如我从与 Microsoft 的支持电话中了解到的那样)。

我想这与 Python 不支持可变长度后向断言这一事实​​有关,但它还不够聪明,无法弄清楚 \1 将始终是固定长度的。为什么在编译正则表达式时它不抱怨这个,我不能说。

有趣的是:

>>> print (re.sub(r'.(?<!\0)', r'(\g<0>)', test))
(x)(A)(A)(A)(A)(A)(y)(B)(B)(B)(B)(z)
>>>
>>> re.compile(r'(.*)(?<!\1)') # This should trigger an error but doesn't!
<_sre.SRE_Pattern object at 0x00000000026A89C0>

所以最好不要在 Python 的后向断言中使用反向引用。正向后视也好不到哪里去(它在这里也匹配,就好像它是正向前瞻一样):

>>> print (re.sub(r'(.)(?<=\1)', r'(\g<0>)', test))
x(A)(A)(A)(A)Ay(B)(B)(B)Bz

我什至无法猜测这里发生了什么:

>>> print (re.sub(r'(.+)(?<=\1)', r'(\g<0>)', test))
x(AA)(A)(A)Ay(BB)(B)Bz

【讨论】:

猜你喜欢
  • 2014-01-12
  • 1970-01-01
  • 1970-01-01
  • 2012-10-30
  • 1970-01-01
  • 2023-03-15
  • 1970-01-01
  • 2012-10-22
  • 1970-01-01
相关资源
最近更新 更多