2012-04-23 26 views
10

從我的理解,不可能回顧後用反向引用

(.)(?<!\1) 

不應該相匹配。實際上,php的preg_replace甚至拒絕編譯這個,ruby的gsub也是如此。蟒蛇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) 

注意,不像pcreregex還允許可變寬度lookbehinds:

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

最終,regex將要被包括在標準庫,如PEP 411中所述。

+3

它匹配好像你使用了'(。)(?!\ 1)'。 – FakeRainBrigand 2012-04-23 10:56:08

回答

5

這看起來像一個限制Python的re模塊(說「錯誤」,因爲我從微軟支持呼叫了解到的好方法)。

我想這與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 
+0

謝謝,這證實了我對這是一個錯誤的感受。 – georg 2012-04-24 11:56:08

+0

Python看起來並不是唯一的語言在lookbehind斷言反向引用有問題:http://stackoverflow.com/questions/2734977/backreferences-in-lookbehind/2735611#2735611 – 2012-05-02 06:06:14