据我了解,
(.)(?<!\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
还允许可变宽度后视:
print (regex.sub(r'(.)(?<![A-Z]+)', r'(\g<0>)', test))
## (x)AAAAA(y)BBBB(z)
最终,regex
将包含在标准库中,如 PEP 411 中所述.
最佳答案
这看起来确实像是 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
关于python - 不可能的反向引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10279055/