2012-11-30 13 views
7

Sto cercando di far corrispondere del testo se non ha un altro blocco di testo nelle sue vicinanze. Ad esempio, mi piacerebbe abbinare lo "bar" se lo "foo" non lo precede. Posso abbinare "bar" se "foo" non fa immediatamente precedono usando aspetto negativo indietro in questo regex:Ricerca di regressione negativa con un carattere jolly

/(?<!foo)bar/ 

ma mi piace anche di non corrispondere "foo 12345 bar". Ho provato:

/(?<!foo.{1,10})bar/ 

ma utilizzando un carattere jolly + un intervallo sembra essere un'espressione regolare non valida in Ruby. Sto pensando al problema?

risposta

9

Ci stai pensando nel modo giusto. Ma sfortunatamente le guardie di solito sono di lunghezza fissa. L'unica grande eccezione è il motore regex di .NET, che consente di quantificare la ripetizione all'interno di lookbehind. Ma dal momento che hai solo bisogno di un lookback negativo e non di un lookahead anche tu. C'è un trucco per te. Invertire la stringa, quindi cercare di far corrispondere:

/rab(?!.{0,10}oof)/ 

poi invertire il risultato della partita o sottrarre la posizione corrispondente dalla lunghezza della stringa, se è quello che siete dopo.

Ora dalla regex che hai dato, suppongo che questa fosse solo una versione semplificata di ciò che effettivamente ti serve. Naturalmente, se lo bar è un modello complesso, è necessario riflettere su come reinserirlo correttamente.

Nota che se il tuo schema richiede sia longheroni di aspetto variabile che lookahead, sarebbe più difficile risolverli. Inoltre, nel tuo caso, sarebbe possibile per decostruire il tuo lookbehind in più quelle di lunghezza variabile (perché si utilizzano né +*):

/(?<!foo)(?<!foo.)(?<!foo.{2})(?<!foo.{3})(?<!foo.{4})(?<!foo.{5})(?<!foo.{6})(?<!foo.{7})(?<!foo.{8})(?<!foo.{9})(?<!foo.{10})bar/ 

Ma non è tutto ciò che bello, vero?

+1

Invertire la stringa è stata un'idea interessante. Grazie! –

3

Come già citato da m.buettner, le espressioni regolari in Ruby devono essere di lunghezza fissa e vengono descritte nel documento. Quindi, non è possibile inserire un quantificatore all'interno di un lookbehind.

Non è necessario controllare tutto in un solo passaggio. Prova a fare più passaggi delle corrispondenze regolari per ottenere quello che vuoi. Partendo dal presupposto che l'esistenza di foo di fronte a una singola istanza di bar rompe la condizione indipendentemente dal fatto che v'è un altro bar, quindi

string.match(/bar/) and !string.match(/foo.*bar/) 

vi darà ciò che si vuole per l'esempio.

Se si desidera invece la partita per avere successo con bar foo bar, allora si può fare questo

string.scan(/foo|bar/).first == "bar" 
+0

Ciò è problematico se l'idea è di recuperare effettivamente una corrispondenza. Supponi di avere "bar foo bar". La regex che l'OP ha provato avrebbe recuperato la prima 'barra'. La tua soluzione affermerebbe che non c'è corrispondenza. (A parte il fatto che hai omesso l'euristica "fino a 10 caratteri") –

+0

@ m.buettner Tu ed io abbiamo diverse interpretazioni con la domanda. – sawa

+1

Sicuro. Ecco perché non dico che la tua soluzione sia sbagliata.Ma trovo importante che tali presupposti e differenze siano dichiarati. Perché potrebbero non essere evidenti all'OP o a chiunque altro trovi questa domanda in futuro. –

Problemi correlati