2012-01-27 15 views
17

Sto cercando di utilizzare i lookbehind in un'espressione regolare e non sembra funzionare come mi aspettavo. Quindi, questo non è il mio vero utilizzo, ma per semplificare farò un esempio. Immagina di voler abbinare "esempio" a una stringa che dice "questo è un esempio". Così, secondo la mia comprensione di lookbehinds questo dovrebbe funzionare:L'espressione regolare Lookbehind non funziona con i quantificatori ('+' o '*')

(?<=this\sis\san\s*?)example 

Cosa dovrebbe fare è trovare "Questa è una", quindi i caratteri di spazio e, infine, corrisponde alla parola "esempio". Ora, non funziona e non capisco perché, è impossibile usare '+' o '*' all'interno di lookbehinds?

Ho anche provato quei due e funzionano correttamente, ma che non soddisfano i miei bisogni:

(?<=this\sis\san\s)example 
this\sis\san\s*?example 

Sto usando questo sito per testare le mie espressioni regolari: http://gskinner.com/RegExr/

+5

questo ha bisogno di un tag che identifica la lingua o l'ambiente dove li usi Le espressioni regolari di .NET gestiscono questo senza problemi. – Joey

+0

Avviso! Se la tua espressione regolare funzionasse come vuoi, corrisponderà anche a 'example' di questo:' this is anexample'. Quindi, se non vuoi che tu debba rimuovere il '?' – noob

+0

micha: Probabilmente dovrebbero semplicemente cambiare * in un '+'. Rimuovere il '' 'non ha alcun effetto a riguardo. Ma in realtà, '*?' Come quantificatore è inutile e non necessario in questo caso poiché non ci sono più spazi bianchi da abbinare dopo, quindi '\ s *?' È equivalente a '\ s *'. – Joey

risposta

15

Molte librerie di espressione regolare non consentono solo espressioni severe da utilizzare in sguardo dietro affermazioni del tipo:

  • corrispondenza solo corde della stessa lunghezza fissa: (?<=foo|bar|\s,\s) (tre caratteri)
  • corrispondere solo stringhe di lunghezze fisse: (?<=foobar|\r\n) (ciascun ramo con lunghezza fissa)
  • solo stringhe corrispondenza con una lunghezza limite superiore: (?<=\s{,4}) (fino a quattro ripetizioni)

Il motivo di queste limitazioni è principalmente dovuto al fatto che tali librerie non sono in grado di elaborare le espressioni regolari al contrario o solo in un sottoinsieme limitato.

Un'altra ragione potrebbe essere quella di evitare che gli autori costruiscano espressioni regolari troppo complesse e pesanti da elaborare in quanto hanno un cosiddetto numero pathological behavior (vedere anche ReDoS).

Vedere anche section about limitations of look-behind assertions su Regular-Expressions.info.

+0

In [la mia risposta a questa domanda] (https://stackoverflow.com/questions/17286667/regular-expression-using-negative-lookbehind-non -working-in-notepad/48727748 # 48727748), ho elencato alcune strategie/soluzioni alternative dopo che mi sono imbattuto in questa limitazione sui lookbehind negativi. Spero che possa aiutare anche altri! – Marathon55

0

maggior parte dei motori di regex don' t supporto di espressioni di lunghezza variabile per affermazioni di tipo "lookbehind".

+1

È solo la vista che è problematica. Lookahead può essere qualsiasi cosa in tutti i motori regex che lo supportano. – Joey

+0

@Joey true, modificato per una maggiore precisione. :) – Amber

3

Cosa Ambra ha detto è vero, ma si può lavorare intorno ad esso con un altro approccio: Un non-gruppo di cattura parentesi

(?<=this\sis\san)(?:\s*)example 

che lo rendono una lunghezza fissa guardare dietro, così dovrebbe funzionare.

+1

È lo stesso come '(? <= This \ sis \ san) \ s *? Example' che significa che corrisponde anche agli spazi e per le tue informazioni' (?: '') 'Rende il processo più lento. – noob

+0

micha, mi preoccuperei di più della parte corrispondente in quel caso piuttosto che delle prestazioni. Ottengo in media 0,02451781 ms con il gruppo non-capuring e 0,02370844 ms senza di esso. Non penso che sia una differenza significativa. – Joey

+1

@micha No. Non è lo stesso. È un gruppo * non-catturante *. La mia regex corrisponde solo a 'example' (senza spazi iniziali), ma il tuo esempio * include * spazi iniziali – Bohemian

9

Ehi, se non stai usando la variabile python guarda dietro l'asserzione puoi ingannare il motore regex evadendo la corrispondenza e ricominciando usando \K.

Questo sito spiega bene .. http://www.phpfreaks.com/blog/pcre-regex-spotlight-k ..

Ma più o meno quando si dispone di un'espressione che si corrispondono e si desidera ottenere tutto alle spalle usando \ K costringerà a ricominciare da capo ...

Esempio:

string = '<a this is a tag> with some information <div this is another tag > LOOK FOR ME </div>' 

corrispondenza /(\<a).+?(\<div).+?(\>)\K.+?(?=\<div)/ farà sì che l'espressione regolare per riavviare dopo è partita la fine div tag in modo l'espressione regolare non includerà che nel risultato. Lo (?=\div) farà in modo che il motore ottenga tutto davanti al tag div di fine

+1

funziona con ruby ​​2.x ma fallisce con 1.9 e jruby 1.7.x; commento originale: bravo, sono sorpreso di non aver mai conosciuto questa funzione. Impara a formattare il codice nell'editor e sarai inestimabile – akostadinov

+0

'\ K' è davvero utile! Non so cosa avrei fatto senza di esso ... –

0

È possibile utilizzare le sotto-espressioni.

(this\sis\san\s*?)(example) 

Quindi, per recuperare il gruppo 2, "esempio", $2 per regex, o \2 se si sta utilizzando una stringa di formato (come ad di pitone re.sub)