tutorial - Come negare una parola specifica in regex?




javascript python (9)

A meno che le prestazioni non siano di estrema importanza, spesso è più semplice eseguire i risultati con un secondo passaggio, ignorando quelli che corrispondono alle parole che si desidera negare.

Le espressioni regolari di solito indicano che si sta eseguendo script o qualche tipo di attività a bassa prestazione, quindi è consigliabile trovare una soluzione facile da leggere, facile da comprendere e di facile manutenzione.

So che posso annullare il gruppo di caratteri come in [^bar] ma ho bisogno di un'espressione regolare in cui la negazione si applica alla parola specifica - quindi nel mio esempio come faccio a negare una "bar" effettiva e non "any chars in bar" ?


Mi sono imbattuto in questo thread del forum mentre cercavo di identificare una espressione regolare per la seguente dichiarazione inglese:

Data una stringa di input, abbina tutto a meno che questa stringa di input non sia esattamente 'bar'; per esempio voglio abbinare 'barriera' e 'disbar' così come 'foo'.

Ecco la regex che ho trovato

^(bar.+|(?!bar).*)$

La mia traduzione inglese della regex è "corrisponde alla stringa se inizia con" bar "e ha almeno un altro carattere, o se la stringa non inizia con" bar ".



Potresti utilizzare un look-ahead o look-behind negativo :

^(?!.*?bar).*
^(.(?<!bar))*?$

O usa solo le basi:

^(?:[^b]+|b(?:$|[^a]|a(?:$|[^r])))*$

Questi corrispondono a tutto ciò che non contiene bar .


Ho solo pensato a qualcos'altro che potrebbe essere fatto. È molto diverso dalla mia prima risposta, in quanto non utilizza espressioni regolari, quindi ho deciso di fare un secondo post di risposta.

Usa il metodo split() tua lingua di scelta equivalente sulla stringa con la parola per negare come argomento per cosa dividere. Un esempio di Python:

>>> text = 'barbarasdbarbar 1234egb ar bar32 sdfbaraadf'
>>> text.split('bar')
['', '', 'asd', '', ' 1234egb ar ', '32 sdf', 'aadf']

Il bello di farlo in questo modo, almeno in Python (non ricordo se la funzionalità sarebbe la stessa in, ad esempio, Visual Basic o Java), è che ti consente di sapere indirettamente quando "barra" è stata ripetuta in la stringa dovuta al fatto che le stringhe vuote tra "barre" sono incluse nell'elenco dei risultati (sebbene all'inizio la stringa vuota sia dovuta alla presenza di una "barra" all'inizio della stringa). Se non lo desideri, puoi semplicemente rimuovere le stringhe vuote dall'elenco.


La risposta accettata è buona, ma in realtà è un aggiramento per la mancanza di un operatore di negazione di sottoespressione semplice nelle espressioni regex. Questo è il motivo per cui grep --invert-match esce. Quindi in * nix, puoi ottenere il risultato desiderato usando pipe e una seconda regex.

grep 'something I want' | grep --invert-match 'but not these ones'

Ancora una soluzione, ma forse più facile da ricordare.


La seguente regex farà ciò che vuoi (purché siano supportati lookbehind e lookaheads negativi), facendo corrispondere le cose correttamente; l'unico problema è che combina i singoli caratteri (ad esempio, ogni corrispondenza è un singolo carattere piuttosto che tutti i caratteri tra due "barre" consecutive), con il rischio potenziale di un sovraccarico elevato se si lavora con stringhe molto lunghe.

b(?!ar)|(?<!b)a|a(?!r)|(?<!ba)r|[^bar]

Spero di completare la risposta

Poiché Chris ha specificato Regex Tutorial è la migliore risorsa per l'apprendimento delle espressioni regolari.

Tuttavia, ha davvero consumato tempo per leggere.

Faccio un cheatsheet per la convenienza mnemonica.
[] , () , {} leader di ogni classe che è facile da ricordare.

Regex =
{'single_character': ['[]', '.', {'negate':'^'}],
 'capturing_group' : ['()', '|', '\\', 'backreferences and named group'],
 'repetition'      : ['{}', '*', '+', '?', 'greedy v.s. lazy'],
 'anchor'          : ['^', '\b', '$'],
 'non_printable'   : ['\n', '\t', '\r', '\f', '\v'],
 'shorthand'       : ['\d', '\w', '\s'],
 }

Supponendo che tu voglia solo disabilitare le stringhe che corrispondono completamente alla regex (cioè, mmbla va bene, ma mm non lo è), questo è quello che vuoi:

^(?!(?:m{2}|t)$).*$

(?!(?:m{2}|t)$) è un lookahead negativo; dice "partendo dalla posizione corrente, i seguenti caratteri non sono mm o t , seguiti dalla fine della stringa." L'ancoraggio di inizio ( ^ ) all'inizio assicura che il lookahead sia applicato all'inizio della stringa. Se questo riesce, il .* Va avanti e consuma la stringa.

Per tua informazione, se stai usando il metodo matches() di Java, non hai davvero bisogno del ^ e del $ finale, ma non fanno alcun danno. Il $ all'interno del lookahead è richiesto, però.





regex