2012-04-23 11 views
10

Dalla mia comprensione,lookbehind impossibile con un backreference

(.)(?<!\1) 

non deve mai corrispondere. In realtà, php's preg_replace si rifiuta anche di compilare questo e così fa rubino gsub. Il modulo python re sembra avere un parere diverso però:

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

Risultato:

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

Qualcuno può fornire una spiegazione ragionevole per questo comportamento?

Aggiornamento

Questo comportamento sembra essere a limitation nel modulo re. Il modulo alternativa regex sembra per gestire gruppi di affermazioni correttamente:

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) 

Si noti che diversamente pcre, regex permette anche lookbehinds larghezza variabile:

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

Alla fine, regex sta per essere inclusi nello standard libreria, come indicato in PEP 411.

+3

E 'corrispondenti come se hai usato '(.) (?! \ 1)'. – FakeRainBrigand

risposta

5

Questo sembra un limite (bel modo di dire "bug", come ho appreso da una chiamata di supporto con Microsoft) nel modulo Python re.

Credo che abbia a che fare con il fatto che Python non supporta lunghezza variabile lookbehind affermazioni, ma non è abbastanza intelligente da capire a lunghezza fissa che sarà sempre \1. Perché non si lamenta di questo durante la compilazione della regex, non posso dire.

Stranamente:

>>> 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> 

Quindi meglio non utilizzare backreference in asserzioni che guardano indietro in Python. lookbehind positivo non è molto meglio (che corrisponda anche qui come se fosse un lookahead positiva):

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

E non posso nemmeno immaginare quello che sta succedendo qui:

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

Grazie, questo conferma i miei sentimenti per questo essere un bug. – georg

+0

Python non è apparentemente l'unico linguaggio che ha problemi con il backreference nelle asserzioni lookbehind: http://stackoverflow.com/questions/2734977/backreferences-in-lookbehind/2735611#2735611 –

Problemi correlati