根据我的理解,
(.)(?<!\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)
有人能为这种行为提供合理的解释吗?
此行为在re
模块中显示为a limitation。替代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中所述。
答案 0 :(得分:5)
在Python re
模块中,这看起来像一个限制(很好地说“bug”,就像我从微软的支持电话中学到的那样)。
我想这与Python不支持可变长度的lookbehind断言这一事实有关,但它并不足以弄明白\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