12

据我了解,

(.)(?<!\1)

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

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

结果:

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

任何人都可以为这种行为提供合理的解释吗?

更新

此行为似乎是模块中的一个限制。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)

请注意,与, 不同的是pcreregex它还允许可变宽度的后视:

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

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

4

1 回答 1

6

这看起来确实像 Pythonre模块中的一个限制(说“bug”的好方法,正如我从与 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
于 2012-04-23T11:17:53.487 回答