2009-08-06 10 views
443

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 un effettivo "bar" e non "any chars in bar"?Come negare una parola specifica nell'espressione regolare?

+1

Possibile duplicato di [Espressione regolare per corrispondere a una riga che non contiene una parola?] (Http: // stackoverflow.it/questions/406230/regular-expression-to-match-line-that-doesnt-contain-a-word) –

risposta

480

Un ottimo modo per farlo è quello di utilizzare negative lookahead:

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

Questo dice tutto (probabilmente avrei iniziato con (?! Bar) e costruito). Non vedo perché altre persone lo rendano così complicato. – Beta

+24

Sfortunatamente, questo non funziona con tutte le lingue. – JAB

+4

carattere iniziale di linea all'inizio fa un buon lavoro. – dhblah

31

Si potrebbe utilizzare un negative look-ahead or look-behind:

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

Oppure utilizzare solo nozioni di base:

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

Questi tutti i match tutto ciò che non contiene bar.

+0

Quali lingue non supportano (negativo) look-behind e/o (negativo) look-ahead in regex ? – JAB

+4

Penso che il punto sia stato fatto, guardando il tuo modello non è affatto chiaro che tutto quello che stai facendo è rifiutare la parola "barra". –

+0

@Bryan: E, in effetti, non rifiuta la parola "barra". Rifiuta semplicemente "b" quando seguito da "ar". – JAB

57

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 è possibile trovare una soluzione facile da leggere, facile da comprendere e di facile manutenzione.

40

La regex seguente farà ciò che si desidera (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 conseguente potenziale di un sovraccarico elevato se si lavora con stringhe molto lunghe.

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

Invece di quegli aggiornamenti multipli che ci costringono a leggere le risposte sbagliate prima di arrivare a la tua risposta finale, perché non riscrivere la tua risposta per essere completa, ma senza le parti cattive un po 'confuse? Se a qualcuno interessa davvero la cronologia delle modifiche, possono utilizzare le funzionalità integrate di questo sito. –

+12

Sono passati due anni e mezzo da quando ho scritto questa risposta, ma sono sicuro. – JAB

+2

dannazione che fa male, prova questo (? :(? Bar).) * – Bob

1

solo pensato di 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.

Utilizzare il metodo corrispondente alla stringa split() nella stringa con la parola da escludere come argomento su cosa dividere. Un esempio di utilizzo di Python:

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

La cosa bella di fare in questo modo, in Python, almeno (non ricordo se la funzionalità sarebbe lo stesso, per esempio, Visual Basic o Java), è che ti consente di sapere indirettamente quando "barra" è stata ripetuta nella stringa a causa del fatto che le stringhe vuote tra "barre" sono incluse nell'elenco dei risultati (anche se la stringa vuota all'inizio è dovuta al fatto che esiste una "barra" "all'inizio della stringa). Se non lo desideri, puoi semplicemente rimuovere le stringhe vuote dall'elenco.

+0

La domanda chiede specificamente regex ... –

+2

@Ajk_P sì, ma questo tipo di risposte può aiutare l'OP pensare fuori dagli schemi, hanno potuto essere fissati con espressioni regolari non rendendosi conto che potrebbe essere risolto senza di loro. – Petruza

21

mi sono imbattuto in questo thread del forum durante il tentativo di individuare una regex per la seguente dichiarazione inglese:

Dato una stringa di input, match tuttoa meno questa stringa di input è esattamente 'bar'; per esempio voglio abbinare 'barriera' e 'disbar' così come 'foo'.

Ecco l'espressione regolare che mi è venuta

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

Il mio inglese del regex è "hanno la stringa se inizia con 'bar' e ha almeno un altro personaggio, o se il stringa non iniziare con 'bar'

+0

@ReReqest - avrai più possibilità di rispondere a questa domanda se la pubblichi come una domanda separata. In questo modo puoi fornire il link a questa domanda se vuoi. Per la sostanza della questione - sembra male, ma io non sono espressioni regolari guru – Bostone

+1

Questo era quello che stavo cercando. Abbina davvero tutto tranne bar. –

1

ho avuto una lista di nomi di file, e ho voluto escludere alcune quelli, con questo tipo di comportamento (Ruby):.

files = [ 
    'mydir/states.rb',  # don't match these 
    'countries.rb', 
    'mydir/states_bkp.rb', # match these 
    'mydir/city_states.rb' 
] 
excluded = ['states', 'countries'] 

# set my_rgx here 

result = WankyAPI.filter(files, my_rgx) # I didn't write WankyAPI... 
assert result == ['mydir/city_states.rb', 'mydir/states_bkp.rb'] 

Ecco la mia soluzione:

excluded_rgx = excluded.map{|e| e+'\.'}.join('|') 
my_rgx = /(^|\/)((?!#{excluded_rgx})[^\.\/]*)\.rb$/ 

mie ipotesi per questa applicazione:

  • La stringa da escludere è all'inizio dell'ingresso, o immediatamente dopo una barra.
  • Le stringhe consentite terminano con .rb.
  • I nomi file consentiti non hanno un carattere . prima dello .rb.
3

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 delle uscite grep --invert-match. 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.

17

Soluzione:

^(?!.*STRING1|.*STRING2|.*STRING3).*$ 

xxxxxx OK

xxxSTRING1xxx KO (è se si desidera)

xxxSTRING2xxx KO (è se si desidera)

xxxSTRING3xxx KO (è se si desidera)

+1

grazie, questo mi ha dato informazioni in più che mi serviva per più parole – RozzA

1

spero per completare la risposta

Come il Chris specificato Regex Tutorial è un miglior risorsa per imparare regex.

Tuttavia, ha davvero consumato il tempo di 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'], 
} 
Problemi correlati