2010-01-02 7 views
5

A seguito di un previous question in cui ho chiesto:Utilizzando regex per abbinare stringa tra due stringhe escludendo stringhe

Come posso usare un'espressione regolare per abbinare il testo che si trova tra due stringhe, se quei due stringhe sono racchiuse altre due stringhe, con qualsiasi quantità di testo tra le stringhe interne ed esterne?

ho avuto questa risposta:

/outer-start.*?inner-start(.*?)inner-end.*?outer-end/ 

Ora vorrei sapere come escludere determinate stringhe dal testo tra le corde di cinta esterne e le stringhe di cinta interno.

Per esempio, se ho questo testo:

esterno iniziare del testo interno-iniziaretesto-che-i-wantinterno-end altro testo esterno -end

Vorrei "un po 'di testo" e "un po' di testo" per non contenere la parola "non voluto".

In altre parole, questo è OK:

esterno-start alcuni volevano testo interno-starttesto-che-i-wantinterno-end il testo più ricercato esterno-end

Ma questo non è OK:

012.

esterno iniziare del testo indesiderato interno-starttesto-che-i-wantinterno-end ancora un po 'indesiderato testo esterno-end

O per spiegare ulteriormente , l'espressione tra delimitatori esterni e interni nella precedente risposta sopra dovrebbe escludere la parola "indesiderato".

È facile abbinare le espressioni regolari?

+0

Che cosa stai cercando di fare? – Gumbo

risposta

5

Sostituire il primo e l'ultimo (ma non il mezzo) .*? con (?:(?!unwanted).)*?. (Dove (?:...) è un gruppo non-cattura, e (?!...) è un lookahead negativo.)

Tuttavia, questo finisce subito con casi d'angolo e avvertimenti in una vera e propria (invece di esempio) usare, e se si interroghi su ciò che stai davvero facendo (con esempi reali, anche se sono semplificati, invece di esempi inventati), probabilmente otterrai risposte migliori.

+0

Questa è una soluzione migliore della mia. –

0

Prova a sostituire l'ultimo. *? con: (?! (. * testo indesiderato. *))

Ha funzionato?

+1

Se non sei sicuro (e anche se pensi di essere sicuro), dovresti testare il tuo pattern localmente (o su un sito come http://codepad.org/), motivo per cui le domande di regex hanno bisogno di buoni esempi (entrambi passando e fallendo). –

1

È possibile sostituire .*? con

([^u]|u[^n]|un[^w]|unw[^a]|unwa[^n]|unwan[^t]|unwant[^e]|unwante[^d])*? 

Si tratta di una soluzione in regex "puro"; la lingua che stai utilizzando potrebbe consentire di utilizzare un costrutto più elegante.

1

Non è possibile farlo facilmente con espressioni regolari, ma alcuni sistemi come Perl hanno estensioni che rendono più semplice. Un modo è quello di utilizzare un look-ahead negativo affermazione:

/outer-start(?:u(?!nwanted)|[^u])*?inner-start(.*?)inner-end.*?outer-end/ 

La chiave è quella di dividere il "indesiderato" in ("u" non seguita da "Nwanted") o (non "u"). Ciò consente al pattern di avanzare, ma troverà e rifiuterà tutte le stringhe "indesiderate".

Le persone possono iniziare a odiare il codice se si fa molto di questo però. ;)

2

Una domanda migliore da porsi di "come si fa con le espressioni regolari?" è "come faccio a risolvere questo problema?". In altre parole, non restare bloccato nel cercare di risolvere un grosso problema con le espressioni regolari. Se riesci a risolvere metà problema con le espressioni regolari, fallo, quindi risolvi l'altra metà con un'altra espressione regolare o qualche altra tecnica.

Ad esempio, eseguire un passaggio sui dati ottenendo tutte le corrispondenze, ignorando il testo indesiderato (leggi: ottieni risultati con e senza il testo indesiderato). Quindi, passa il set ridotto di dati e elimina i risultati che contengono il testo indesiderato. Questo tipo di soluzione è più facile da scrivere, più facile da capire e più facile da mantenere nel tempo. E per qualsiasi problema tu abbia bisogno di risolvere con questo approccio, sarà sufficientemente veloce.

0

Tola, facendo risorgere questa domanda perché aveva una soluzione regex piuttosto semplice che non era menzionata. Questo problema è un classico caso della tecnica spiegata in questa domanda di "regex-match a pattern, excluding..."

L'idea è quella di costruire un'alternanza (una serie di |), dove i lati sinistro partita ciò che non vogliono al fine di ottenerlo fuori mano ... allora l'ultimo lato del | corrisponde a ciò che vogliamo e lo cattura nel Gruppo 1. Se il Gruppo 1 è impostato, lo recuperi e hai una corrispondenza.

Quindi cosa non vogliamo?

In primo luogo, vogliamo eliminare l'intero blocco esterno se c'è unwanted tra outer-start e inner-start. È possibile farlo con:

outer-start(?:(?!inner-start).)*?unwanted.*?outer-end 

Questo sarà alla sinistra del primo |. Corrisponde a un intero blocco esterno.

In secondo luogo, vogliamo eliminare l'intero blocco esterno se c'è unwanted tra inner-end e outer-end. È possibile farlo con:

outer-start(?:(?!outer-end).)*?inner-end(?:(?!outer-end).)*?unwanted.*?outer-end 

Questo sarà il mezzo |.Sembra un po 'complicato perché vogliamo essere sicuri che il "pigro" *? non superi la fine di un blocco in un altro blocco.

In terzo luogo, abbiniamo e catturiamo ciò che vogliamo. Si tratta di:

inner-start\s*(text-that-i-want)\s*inner-end 

Così tutta la regex, in modalità senza spaziatura, è:

(?xs) 
outer-start(?:(?!inner-start).)*?unwanted.*?outer-end # dont want this 
| # OR (also don't want that) 
outer-start(?:(?!outer-end).)*?inner-end(?:(?!outer-end).)*?unwanted.*?outer-end 
| # OR capture what we want 
inner-start\s*(text-that-i-want)\s*inner-end 

Su this demo, guardare le acquisizioni del gruppo 1 sulla destra: Contiene quello che vogliamo, e solo per il blocco giusto.

In Perl e PCRE (utilizzato ad esempio in PHP), non è nemmeno necessario guardare il Gruppo 1: è possibile forzare la regex a saltare i due blocchi che non vogliamo. La regex diventa:

(?xs) 
(?: # non-capture group: the things we don't want 
outer-start(?:(?!inner-start).)*?unwanted.*?outer-end # dont want this 
| # OR (also don't want that) 
outer-start(?:(?!outer-end).)*?inner-end(?:(?!outer-end).)*?unwanted.*?outer-end 
) 
(*SKIP)(*F) # we don't want this, so fail and skip 
| # OR capture what we want 
inner-start\s*\Ktext-that-i-want(?=\s*inner-end) 

See demo: corrisponde direttamente ciò che si desidera.

La tecnica è spiegata in dettaglio nella domanda e nell'articolo di seguito.

Riferimento