Espressione regolare per trovare una riga che non contiene una parola

Jan 02 2009

So che è possibile abbinare una parola e quindi invertire le corrispondenze utilizzando altri strumenti (ad esempio grep -v). Tuttavia, è possibile abbinare le righe che non contengono una parola specifica, ad esempio hedeutilizzando un'espressione regolare?

Ingresso:

hoho
hihi
haha
hede

Codice:

grep "<Regex for 'doesn't contain hede'>" input

Uscita desiderata:

hoho
hihi
haha

Risposte

6170 BartKiers Jan 02 2009 at 16:55

La nozione che regex non supporti la corrispondenza inversa non è del tutto vera. Puoi imitare questo comportamento utilizzando look-around negativi:

^((?!hede).)*$

L' espressione regolare sopra corrisponderà a qualsiasi stringa o riga senza interruzione di riga, non contenente la (sotto) stringa "hede". Come accennato, questo non è qualcosa in cui regex è "bravo" (o dovrebbe fare), ma comunque è possibile.

E se hai bisogno di abbinare anche i caratteri di interruzione di riga, usa il modificatore DOT-ALL (il finale snel seguente schema):

/^((?!hede).)*$/s

o usalo in linea:

/(?s)^((?!hede).)*$/

(dove /.../sono i delimitatori regex, cioè non fanno parte del pattern)

Se il modificatore DOT-ALL non è disponibile, puoi imitare lo stesso comportamento con la classe del personaggio [\s\S]:

/^((?!hede)[\s\S])*$/

Spiegazione

Una stringa è solo un elenco di ncaratteri. Prima e dopo ogni carattere, c'è una stringa vuota. Quindi un elenco di ncaratteri avrà n+1stringhe vuote. Considera la stringa "ABhedeCD":

    ┌──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┐
S = │e1│ A │e2│ B │e3│ h │e4│ e │e5│ d │e6│ e │e7│ C │e8│ D │e9│
    └──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┘

index    0      1      2      3      4      5      6      7

dove esono le stringhe vuote. L'espressione regolare (?!hede).guarda avanti per vedere se non c'è sottostringa "hede"da vedere, e se è così (quindi si vede qualcos'altro), il .(punto) corrisponderà a qualsiasi carattere tranne un'interruzione di riga. I look-around sono anche chiamati asserzioni di larghezza zero perché non consumano alcun carattere. Affermano / convalidano solo qualcosa.

Quindi, nel mio esempio, ogni stringa vuota viene prima convalidata per vedere se non c'è "hede"più avanti, prima che un carattere venga consumato dal .(punto). La regex (?!hede).farà che solo una volta, per cui è avvolto in un gruppo, e ripetuto zero o più volte: ((?!hede).)*. Infine, l'inizio e la fine dell'input sono ancorati per assicurarsi che l'intero input venga consumato:^((?!hede).)*$

Come si può vedere, l'ingresso "ABhedeCD"non riuscirà perché il e3, l'espressione regolare (?!hede)non riesce (non v'è "hede" più avanti!).

774 FireCoding Mar 17 2011 at 11:21

Nota che la soluzione per non inizia con "hede" :

^(?!hede).*$

è generalmente molto più efficiente della soluzione per non contenere "hede" :

^((?!hede).)*$

Il primo verifica la presenza di "hede" solo nella prima posizione della stringa di input, piuttosto che in ogni posizione.

213 Athena Jan 02 2009 at 14:41

Se lo stai usando solo per grep, puoi usarlo grep -v hedeper ottenere tutte le righe che non contengono hede.

ETA Oh, rileggendo la domanda, grep -vprobabilmente è quello che intendevi per "opzioni degli strumenti".

169 Jessica May 10 2014 at 23:36

Risposta:

^((?!hede).)*$

Spiegazione:

^l'inizio della stringa, (raggruppa e cattura a \ 1 (0 o più volte (corrispondente al maggior numero possibile)),
(?!guarda avanti per vedere se non c'è,

hede la tua corda,

)fine del look-ahead, .qualsiasi carattere eccetto \ n,
)*fine di \ 1 (Nota: poiché stai utilizzando un quantificatore su questa cattura, solo l'ULTIMA ripetizione del pattern acquisito verrà memorizzata in \ 1)
$prima di un \ n facoltativo, e la fine della stringa

104 Hades32 Sep 02 2011 at 22:53

Le risposte fornite vanno perfettamente bene, solo un punto accademico:

Le espressioni regolari nel significato delle scienze informatiche teoriche NON SONO IN GRADO di farlo in questo modo. Per loro doveva assomigliare a questo:

^([^h].*$)|(h([^e].*$|$))|(he([^h].*$|$))|(heh([^e].*$|$))|(hehe.+$) 

Questo fa solo una corrispondenza COMPLETA. Farlo per le partite secondarie sarebbe anche più imbarazzante.

64 RoyTinker Jan 04 2013 at 04:22

Se vuoi che il test regex fallisca solo se l' intera stringa corrisponde, funzionerà quanto segue:

^(?!hede$).*

es. - Se vuoi consentire tutti i valori eccetto "foo" (cioè "foofoo", "barfoo" e "foobar" passeranno, ma "foo" fallirà), usa: ^(?!foo$).*

Ovviamente, se stai verificando l' uguaglianza esatta , una soluzione generale migliore in questo caso è controllare l'uguaglianza delle stringhe, ad es

myStr !== 'foo'

Potresti anche mettere la negazione fuori dal test se hai bisogno di funzionalità regex (qui, insensibilità al maiuscolo / minuscolo e corrispondenza intervallo):

!/^[a-f]oo$/i.test(myStr)

La soluzione regex all'inizio di questa risposta può essere utile, tuttavia, in situazioni in cui è richiesto un test regex positivo (forse da un'API).

57 akim Aug 05 2015 at 14:02

FWIW, poiché i linguaggi regolari (aka linguaggi razionali) sono chiusi sotto complementazione, è sempre possibile trovare un'espressione regolare (aka espressione razionale) che nega un'altra espressione. Ma non molti strumenti lo implementano.

Vcsn supporta questo operatore (che denota {c}, suffisso).

Per prima cosa definisci il tipo delle tue espressioni: le etichette sono lettere ( lal_char) da cui scegliere, aad zesempio (definire l'alfabeto quando si lavora con la complementazione è, ovviamente, molto importante) e il "valore" calcolato per ogni parola è solo un booleano : truela parola è accettata false,, rifiutata.

In Python:

In [5]: import vcsn
        c = vcsn.context('lal_char(a-z), b')
        c
Out[5]: {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z} → 𝔹

quindi inserisci la tua espressione:

In [6]: e = c.expression('(hede){c}'); e
Out[6]: (hede)^c

converti questa espressione in un automa:

In [7]: a = e.automaton(); a

infine, riconvertire questo automa in un'espressione semplice.

In [8]: print(a.expression())
        \e+h(\e+e(\e+d))+([^h]+h([^e]+e([^d]+d([^e]+e[^]))))[^]*

dove di +solito è indicato |, \edenota la parola vuota e di [^]solito è scritto .(qualsiasi carattere). Quindi, con un po 'di riscrittura ()|h(ed?)?|([^h]|h([^e]|e([^d]|d([^e]|e.)))).*.

Puoi vedere questo esempio qui e provare Vcsn online lì .

56 JoshLee Jan 02 2009 at 15:03

Ecco una buona spiegazione del motivo per cui non è facile negare un'espressione regolare arbitraria. Sono d'accordo con le altre risposte, però: se questa è qualcosa di diverso da una domanda ipotetica, allora una regex non è la scelta giusta qui.

51 amobiz Jul 15 2014 at 01:21

Con lookahead negativo, l'espressione regolare può corrispondere a qualcosa che non contiene un pattern specifico. Questo viene risposto e spiegato da Bart Kiers. Ottima spiegazione!

Tuttavia, con la risposta di Bart Kiers, la parte di lookahead metterà alla prova da 1 a 4 caratteri in avanti mentre corrisponde a qualsiasi singolo carattere. Possiamo evitarlo e lasciare che la parte di lookahead controlli l'intero testo, assicurandoci che non ci sia "hede", e poi la parte normale (. *) Può mangiare l'intero testo tutto in una volta.

Ecco la regex migliorata:

/^(?!.*?hede).*$/

Nota che il quantificatore pigro (*?) Nella parte di lookahead negativo è opzionale, puoi invece usare (*) quantificatore avido, a seconda dei tuoi dati: se 'hede' è presente e nella metà iniziale del testo, il quantificatore pigro può essere più veloce; in caso contrario, il quantificatore avido sarà più veloce. Tuttavia, se "hede" non è presente, entrambi sarebbero ugualmente lenti.

Ecco il codice demo .

Per ulteriori informazioni su lookahead, consulta il fantastico articolo: Mastering Lookahead and Lookbehind .

Inoltre, controlla RegexGen.js , un generatore di espressioni regolari JavaScript che aiuta a costruire espressioni regolari complesse. Con RegexGen.js, puoi costruire la regex in un modo più leggibile:

var _ = regexGen;

var regex = _(
    _.startOfLine(),             
    _.anything().notContains(       // match anything that not contains:
        _.anything().lazy(), 'hede' //   zero or more chars that followed by 'hede',
                                    //   i.e., anything contains 'hede'
    ), 
    _.endOfLine()
);
43 Falco Aug 13 2014 at 21:58

Punti di riferimenti

Ho deciso di valutare alcune delle opzioni presentate e di confrontarne le prestazioni, nonché di utilizzare alcune nuove funzionalità. Benchmarking su .NET Regex Engine:http://regexhero.net/tester/

Testo benchmark:

Le prime 7 righe non dovrebbero corrispondere, poiché contengono l'espressione cercata, mentre le 7 righe inferiori dovrebbero corrispondere!

Regex Hero is a real-time online Silverlight Regular Expression Tester.
XRegex Hero is a real-time online Silverlight Regular Expression Tester.
Regex HeroRegex HeroRegex HeroRegex HeroRegex Hero is a real-time online Silverlight Regular Expression Tester.
Regex Her Regex Her Regex Her Regex Her Regex Her Regex Her Regex Hero is a real-time online Silverlight Regular Expression Tester.
Regex Her is a real-time online Silverlight Regular Expression Tester.Regex Hero
egex Hero egex Hero egex Hero egex Hero egex Hero egex Hero Regex Hero is a real-time online Silverlight Regular Expression Tester.
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRegex Hero is a real-time online Silverlight Regular Expression Tester.

Regex Her
egex Hero
egex Hero is a real-time online Silverlight Regular Expression Tester.
Regex Her is a real-time online Silverlight Regular Expression Tester.
Regex Her Regex Her Regex Her Regex Her Regex Her Regex Her is a real-time online Silverlight Regular Expression Tester.
Nobody is a real-time online Silverlight Regular Expression Tester.
Regex Her o egex Hero Regex  Hero Reg ex Hero is a real-time online Silverlight Regular Expression Tester.

Risultati:

I risultati sono iterazioni al secondo come mediana di 3 esecuzioni: numero maggiore = migliore

01: ^((?!Regex Hero).)*$ 3.914 // Accepted Answer 02: ^(?:(?!Regex Hero).)*$                  5.034   // With Non-Capturing group
03: ^(?>[^R]+|R(?!egex Hero))*$ 6.137 // Lookahead only on the right first letter 04: ^(?>(?:.*?Regex Hero)?)^.*$             7.426   // Match the word and check if you're still at linestart
05: ^(?(?=.*?Regex Hero)(?#fail)|.*)$       7.371   // Logic Branch: Find Regex Hero? match nothing, else anything

P1: ^(?(?=.*?Regex Hero)(*FAIL)|(*ACCEPT))  ?????   // Logic Branch in Perl - Quick FAIL
P2: .*?Regex Hero(*COMMIT)(*FAIL)|(*ACCEPT) ?????   // Direct COMMIT & FAIL in Perl

Poiché .NET non supporta i verbi di azione (* FAIL, ecc.) Non ho potuto testare le soluzioni P1 e P2.

Sommario:

Ho provato a testare la maggior parte delle soluzioni proposte, alcune ottimizzazioni sono possibili per alcune parole. Ad esempio, se le prime due lettere della stringa di ricerca non sono uguali, la risposta 03 può essere espansa fino ^(?>[^R]+|R+(?!egex Hero))*$a ottenere un piccolo aumento delle prestazioni.

Ma la soluzione complessiva più leggibile e più veloce dal punto di vista delle prestazioni sembra essere 05 utilizzando un'istruzione condizionale o 04 con il quantificatore possente. Penso che le soluzioni Perl dovrebbero essere ancora più veloci e più facilmente leggibili.

33 kiwalk Feb 23 2011 at 21:00

Non regex, ma ho trovato logico e utile usare greps seriali con pipe per eliminare il rumore.

per esempio. cerca un file di configurazione di apache senza tutti i commenti-

grep -v '\#' /opt/lampp/etc/httpd.conf      # this gives all the non-comment lines

e

grep -v '\#' /opt/lampp/etc/httpd.conf |  grep -i dir

La logica di serial grep è (non un commento) e (corrisponde a dir)

30 CasimiretHippolyte Apr 14 2013 at 10:04

con questo eviti di testare un lookahead su ogni posizione:

/^(?:[^h]+|h++(?!ede))*+$/

equivalente a (per .net):

^(?>(?:[^h]+|h+(?!ede))*)$

Vecchia risposta:

/^(?>[^h]+|h+(?!ede))*$/
24 ikegami Aug 23 2016 at 07:03

Il suddetto (?:(?!hede).)*è ottimo perché può essere ancorato.

^(?:(?!hede).)*$               # A line without hede

foo(?:(?!hede).)*bar           # foo followed by bar, without hede between them

Ma in questo caso sarebbe sufficiente quanto segue:

^(?!.*hede)                    # A line without hede

Questa semplificazione è pronta per l'aggiunta delle clausole "AND":

^(?!.*hede)(?=.*foo)(?=.*bar)   # A line with foo and bar, but without hede
^(?!.*hede)(?=.*foo).*bar       # Same
21 ridgerunner Dec 20 2013 at 10:03

Ecco come lo farei:

^[^h]*(h(?!ede)[^h]*)*$

Preciso e più efficiente rispetto alle altre risposte. Implementa la tecnica dell'efficienza di "srotolamento del ciclo" di Friedl e richiede molto meno backtracking.

18 diyism Mar 23 2012 at 14:24

Se vuoi abbinare un carattere per negare una parola simile a negare la classe di caratteri:

Ad esempio, una stringa:

<?
$str="aaa        bbb4      aaa     bbb7";
?>

Non usare:

<?
preg_match('/aaa[^bbb]+?bbb7/s', $str, $matches);
?>

Uso:

<?
preg_match('/aaa(?:(?!bbb).)+?bbb7/s', $str, $matches);
?>

L'avviso "(?!bbb)."non è né guardare indietro né guardare avanti, è lookcurrent, ad esempio:

"(?=abc)abcde", "(?!abc)abcde"
18 DannieP Nov 25 2018 at 01:26

Una variante, a mio avviso, più leggibile della risposta principale:

^(?!.*hede)

Fondamentalmente, "corrisponde all'inizio della riga se e solo se non contiene" hede "", quindi il requisito è stato tradotto quasi direttamente in regex.

Ovviamente è possibile avere più requisiti di guasto:

^(?!.*(hede|hodo|hada))

Dettagli: l'ancoraggio ^ assicura che il motore di regex non ritenti la corrispondenza in ogni posizione nella stringa, che corrisponderebbe a ogni stringa.

L'ancora ^ all'inizio ha lo scopo di rappresentare l'inizio della linea. Lo strumento grep abbina ogni riga una alla volta, nei contesti in cui stai lavorando con una stringa multilinea, puoi usare il flag "m":

/^(?!.*hede)/m # JavaScript syntax

o

(?m)^(?!.*hede) # Inline flag
14 KevinFegan Apr 27 2013 at 05:28

L'OP non ha specificato o Tagil post per indicare il contesto (linguaggio di programmazione, editor, strumento) in cui verrà utilizzato il Regex.

Per me, a volte ho bisogno di farlo mentre modifico un file usando Textpad.

Textpad supporta alcune espressioni regolari, ma non supporta il lookahead o il lookbehind, quindi sono necessari alcuni passaggi.

Se sto cercando di mantenere tutte le righe che NON contengono la stringa hede, lo farei in questo modo:

1. Cerca / sostituisci l'intero file per aggiungere un "Tag" univoco all'inizio di ogni riga contenente qualsiasi testo.

    Search string:^(.)  
    Replace string:<@#-unique-#@>\1  
    Replace-all  

2. Elimina tutte le righe che contengono la stringa hede( la stringa di sostituzione è vuota):

    Search string:<@#-unique-#@>.*hede.*\n  
    Replace string:<nothing>  
    Replace-all  

3. A questo punto, tutte le righe rimanenti NON contengono la stringa hede. Rimuovi il "Tag" univoco da tutte le righe (la stringa di sostituzione è vuota):

    Search string:<@#-unique-#@>
    Replace string:<nothing>  
    Replace-all  

Ora hai il testo originale con tutte le righe contenenti la stringa hederimosse.


Se sto cercando di fare qualcos'altro solo su righe che NON contengono la stringa hede, lo farei in questo modo:

1. Cerca / sostituisci l'intero file per aggiungere un "Tag" univoco all'inizio di ogni riga contenente qualsiasi testo.

    Search string:^(.)  
    Replace string:<@#-unique-#@>\1  
    Replace-all  

2. Per tutte le righe che contengono la stringa hede, rimuovi il "Tag" univoco:

    Search string:<@#-unique-#@>(.*hede)
    Replace string:\1  
    Replace-all  

3. A questo punto, tutte le righe che iniziano con il "Tag" univoco, NON contengono la stringa hede. Ora posso fare qualcos'altro solo su quelle righe.

4. Quando ho finito, rimuovo il "Tag" univoco da tutte le righe (la stringa di sostituzione è vuota):

    Search string:<@#-unique-#@>
    Replace string:<nothing>  
    Replace-all  
14 PedroGimeno Dec 07 2016 at 04:24

Poiché nessun altro ha dato una risposta diretta alla domanda che è stata posta , lo farò.

La risposta è che con POSIX grepè impossibile soddisfare letteralmente questa richiesta:

grep "<Regex for 'doesn't contain hede'>" input

Il motivo è che POSIX grepè richiesto solo per lavorare con le espressioni regolari di base , che semplicemente non sono abbastanza potenti per svolgere tale compito (non sono in grado di analizzare tutti i linguaggi regolari, a causa della mancanza di alternanza).

Tuttavia , GNU grepimplementa estensioni che lo consentono. In particolare, \|è l'operatore di alternanza nell'implementazione dei BRE da parte di GNU. Se il tuo motore di espressioni regolari supporta l'alternanza, le parentesi e la stella di Kleene ed è in grado di ancorarsi all'inizio e alla fine della stringa, è tutto ciò di cui hai bisogno per questo approccio. Si noti tuttavia che i set negativi [^ ... ]sono molto convenienti oltre a quelli, perché altrimenti è necessario sostituirli con un'espressione della forma (a|b|c| ... )che elenchi ogni carattere che non è nel set, che è estremamente noioso ed eccessivamente lungo, ancora di più se l'intero set di caratteri è Unicode.

Grazie alla teoria del linguaggio formale, possiamo vedere come appare un'espressione del genere. Con GNU grep, la risposta sarebbe qualcosa del tipo:

grep "^\([^h]\|h\(h\|eh\|edh\)*\([^eh]\|e[^dh]\|ed[^eh]\)\)*\(\|h\(h\|eh\|edh\)*\(\|e\|ed\)\)$" input

(trovato con Graal e alcune ulteriori ottimizzazioni fatte a mano).

Puoi anche utilizzare uno strumento che implementa le espressioni regolari estese , come egrep, per sbarazzarti delle barre rovesciate:

egrep "^([^h]|h(h|eh|edh)*([^eh]|e[^dh]|ed[^eh]))*(|h(h|eh|edh)*(|e|ed))$" input

Ecco uno script per testarlo (nota che genera un file testinput.txtnella directory corrente). Molte delle espressioni presentate non superano questo test.

#!/bin/bash
REGEX="^\([^h]\|h\(h\|eh\|edh\)*\([^eh]\|e[^dh]\|ed[^eh]\)\)*\(\|h\(h\|eh\|edh\)*\(\|e\|ed\)\)$" # First four lines as in OP's testcase. cat > testinput.txt <<EOF hoho hihi haha hede h he ah head ahead ahed aheda ahede hhede hehede hedhede hehehehehehedehehe hedecidedthat EOF diff -s -u <(grep -v hede testinput.txt) <(grep "$REGEX" testinput.txt)

Nel mio sistema stampa:

Files /dev/fd/63 and /dev/fd/62 are identical

come previsto.

Per chi è interessato ai dettagli, la tecnica impiegata consiste nel convertire l'espressione regolare che corrisponde alla parola in un automa finito, quindi invertire l'automa cambiando ogni stato di accettazione in non accettazione e viceversa, e quindi riconvertendo la FA risultante in un'espressione regolare.

Come tutti hanno notato, se il tuo motore di espressioni regolari supporta il lookahead negativo, l'espressione regolare è molto più semplice. Ad esempio, con GNU grep:

grep -P '^((?!hede).)*$' input

Tuttavia, questo approccio ha lo svantaggio di richiedere un motore di espressioni regolari di backtracking. Ciò lo rende inadatto nelle installazioni che utilizzano motori di espressioni regolari sicuri come RE2 , motivo per cui preferire l'approccio generato in alcune circostanze.

Utilizzando l'eccellente libreria FormalTheory di Kendall Hopkins , scritta in PHP, che fornisce una funzionalità simile a Grail, e un semplificatore scritto da me stesso, sono stato in grado di scrivere un generatore online di espressioni regolari negative data una frase di input (solo alfanumerico e spazio caratteri attualmente supportati):http://www.formauri.es/personal/pgimeno/misc/non-match-regex/

Per hedeesso uscite:

^([^h]|h(h|e(h|dh))*([^eh]|e([^dh]|d[^eh])))*(h(h|e(h|dh))*(ed?)?)?$

che è equivalente a quanto sopra.

12 aelor Mar 23 2017 at 20:42

Dall'introduzione di ruby-2.4.1, possiamo usare il nuovo operatore assente nelle espressioni regolari di Ruby

dal doc. ufficiale

(?~abc) matches: "", "ab", "aab", "cccc", etc.
It doesn't match: "abc", "aabc", "ccccabc", etc.

Quindi, nel tuo caso ^(?~hede)$fa il lavoro per te

2.4.1 :016 > ["hoho", "hihi", "haha", "hede"].select{|s| /^(?~hede)$/.match(s)}
 => ["hoho", "hihi", "haha"]
10 AvinashRaj Oct 09 2014 at 14:00

Attraverso il verbo PCRE (*SKIP)(*F)

^hede$(*SKIP)(*F)|^.*$

Ciò salta completamente la riga che contiene la stringa esatta hedee corrisponde a tutte le righe rimanenti.

DEMO

Esecuzione delle parti:

Consideriamo la regex di cui sopra dividendola in due parti.

  1. Parte prima del |simbolo. La parte non dovrebbe essere abbinata .

    ^hede$(*SKIP)(*F)
    
  2. Parte dopo il |simbolo. La parte dovrebbe essere abbinata .

    ^.*$
    

PARTE 1

Il motore Regex inizierà la sua esecuzione dalla prima parte.

^hede$(*SKIP)(*F)

Spiegazione:

  • ^ Afferma che siamo all'inizio.
  • hede Corrisponde alla stringa hede
  • $ Afferma che siamo alla fine della riga.

Quindi la riga che contiene la stringa hedeverrebbe trovata. Una volta che il motore delle espressioni regolari vede il verbo seguente (*SKIP)(*F)( Nota: puoi scrivere (*F)come(*FAIL) ), salta e la corrispondenza fallisce. |chiamata alterazione o operatore logico OR aggiunto accanto al verbo PCRE che in tornio corrisponde a tutti i confini esistenti tra ogni carattere su tutte le righe tranne la riga che contiene la stringa esatta hede. Guarda la demo qui . Cioè, cerca di abbinare i caratteri della stringa rimanente. Ora la regex nella seconda parte verrà eseguita.

PARTE 2

^.*$

Spiegazione:

  • ^Afferma che siamo all'inizio. cioè, corrisponde a tutti gli inizi della riga tranne quello nella hederiga. Guarda la demo qui .
  • .*Nella modalità Multiline, .corrisponde a qualsiasi carattere tranne i caratteri di ritorno a capo o di ritorno a capo. E *ripeterebbe il carattere precedente zero o più volte. Quindi .*corrisponderebbe all'intera linea. Guarda la demo qui .

    Ehi, perché hai aggiunto. * Invece di. +?

    Perché .*corrisponderebbe a una riga vuota ma .+non a uno spazio vuoto. Vogliamo abbinare tutte le righe tranne hede, potrebbe esserci la possibilità di righe vuote anche nell'input. quindi devi usare al .*posto di .+. .+ripeterebbe il carattere precedente una o più volte. Vedi .*corrisponde a una riga vuota qui .

  • $ L'ancoraggio di fine linea non è necessario qui.

9 Emma Aug 01 2019 at 09:36

Un'altra opzione è quella di aggiungere un look-ahead positivo e verificare se si hedetrova in un punto qualsiasi della riga di input, lo negheremo, con un'espressione simile a:

^(?!(?=.*\bhede\b)).*$

con i confini delle parole.


L'espressione è spiegata nel pannello in alto a destra di regex101.com , se desideri esplorarla / semplificarla / modificarla, e in questo link , puoi vedere come corrisponderebbe ad alcuni input di esempio, se lo desideri.


Circuito RegEx

jex.im visualizza espressioni regolari:

8 andrewpate Feb 18 2015 at 18:45

Potrebbe essere più gestibile con due espressioni regolari nel codice, una per eseguire la prima corrispondenza e quindi, se corrisponde, eseguire la seconda espressione regolare per verificare i casi anomali che si desidera bloccare, ad esempio, ^.*(hede).*quindi avere una logica appropriata nel codice.

OK, ammetto che questa non è davvero una risposta alla domanda pubblicata e potrebbe anche utilizzare un po 'più di elaborazione rispetto a una singola regex. Ma per gli sviluppatori che sono venuti qui alla ricerca di una soluzione rapida di emergenza per un caso anomalo, questa soluzione non dovrebbe essere trascurata.

6 Kaz Jun 25 2014 at 08:23

Il linguaggio TXR supporta la negazione delle espressioni regolari .

$ txr -c '@(repeat)
@{nothede /~hede/}
@(do (put-line nothede))
@(end)'  Input

Un esempio più complicato: abbina tutte le righe che iniziano con ae finiscono con z, ma non contengono la sottostringa hede:

$ txr -c '@(repeat)
@{nothede /a.*z&~.*hede.*/}
@(do (put-line nothede))
@(end)' -
az         <- echoed
az
abcz       <- echoed
abcz
abhederz   <- not echoed; contains hede
ahedez     <- not echoed; contains hede
ace        <- not echoed; does not end in z
ahedz      <- echoed
ahedz

La negazione dell'espressione regolare non è particolarmente utile da sola, ma quando hai anche l'intersezione, le cose si fanno interessanti, dato che hai un insieme completo di operazioni booleane sugli insiemi: puoi esprimere "l'insieme che corrisponde a questo, tranne per le cose che corrispondono a quello".

4 DanielNyamasyo Dec 21 2016 at 11:55

La seguente funzione ti aiuterà a ottenere l'output desiderato

<?PHP
      function removePrepositions($text){ $propositions=array('/\bfor\b/i','/\bthe\b/i'); 

            if( count($propositions) > 0 ) { foreach($propositions as $exceptionPhrase) { $text = preg_replace($exceptionPhrase, '', trim($text));

                }
            $retval = trim($text);

            }
        return $retval;
    }


?>
2 cloudhopperpilot Mar 26 2019 at 19:21

^((?!hede).)*$è una soluzione elegante, tranne che poiché consuma caratteri non sarai in grado di combinarla con altri criteri. Ad esempio, supponi di voler verificare la non presenza di "hede" e la presenza di "haha". Questa soluzione funzionerebbe perché non consumerà caratteri:

^(?!.*\bhede\b)(?=.*\bhaha\b) 
1 jaytea Oct 11 2017 at 17:12

Come utilizzare i verbi di controllo backtracking di PCRE per trovare una riga che non contiene una parola

Ecco un metodo che non ho mai visto usato prima:

/.*hede(*COMMIT)^|/

Come funziona

In primo luogo, cerca di trovare "hede" da qualche parte nella linea. In caso di successo, a questo punto, (*COMMIT)dice al motore di non solo non tornare indietro in caso di guasto, ma anche di non tentare ulteriori corrispondenze in quel caso. Quindi, proviamo a trovare una corrispondenza con qualcosa che non può corrispondere (in questo caso, ^).

Se una riga non contiene "hede", la seconda alternativa, un sottomodello vuoto, corrisponde correttamente alla stringa dell'oggetto.

Questo metodo non è più efficiente di un lookahead negativo, ma ho pensato di lanciarlo qui nel caso qualcuno lo trovasse elegante e trovasse un uso per altre applicazioni più interessanti.

1 MatthewRideout Apr 29 2020 at 01:53

Volevo aggiungere un altro esempio per se si sta cercando di abbinare una intera linea che contiene la stringa X , ma non contengono anche stringa Y .

Ad esempio, supponiamo di voler controllare se il nostro URL / stringa contiene " gustose prelibatezze ", a condizione che non contenga anche " cioccolato " da nessuna parte.

Questo pattern regex funzionerebbe (funziona anche in JavaScript)

^(?=.*?tasty-treats)((?!chocolate).)*$

(flag globali, multilinea nell'esempio)

Esempio interattivo: https://regexr.com/53gv4

Partite

(Questi URL contengono "leccornie" e inoltre non contengono "cioccolato")

  • example.com/tasty-treats/strawberry-ice-cream
  • example.com/desserts/tasty-treats/banana-pudding
  • example.com/tasty-treats-overview

Non corrisponde

(Questi URL contengono "cioccolato" da qualche parte, quindi non corrispondono anche se contengono "prelibatezze")

  • example.com/tasty-treats/chocolate-cake
  • example.com/home-cooking/oven-roasted-chicken
  • example.com/tasty-treats/banana-chocolate-fudge
  • example.com/dessert/chocolate/tasty-treats
  • example.com/chocolate/tasty-treats/desserts
1 AnasR. Jun 15 2020 at 18:02

Finché hai a che fare con le linee , contrassegna semplicemente le corrispondenze negative e scegli come target il resto .

In effetti, uso questo trucco con sed perché ^((?!hede).)*$non sembra supportato da esso.

Per l'output desiderato

  1. Contrassegna la corrispondenza negativa: (ad es. Righe con hede), utilizzando un carattere non incluso affatto nell'intero testo. Un'emoji potrebbe probabilmente essere una buona scelta per questo scopo.

    s/(.*hede)/🔒\1/g
    
  2. Scegli come target il resto (le stringhe non contrassegnate: ad esempio le linee senza hede). Supponi di voler mantenere solo il target ed eliminare il resto (come vuoi):

    s/^🔒.*//g
    

Per una migliore comprensione

Supponi di voler eliminare il target :

  1. Contrassegna la corrispondenza negativa: (ad es. Righe con hede), utilizzando un carattere non incluso affatto nell'intero testo. Un'emoji potrebbe probabilmente essere una buona scelta per questo scopo.

    s/(.*hede)/🔒\1/g
    
  2. Scegli come target il resto (le stringhe non contrassegnate: ad esempio le linee senza hede). Supponi di voler eliminare il target :

    s/^[^🔒].*//g
    
  3. Rimuovi il segno:

    s/🔒//g
    
user1691651-John Sep 13 2016 at 20:52

Una soluzione più semplice è utilizzare l'operatore not !

L' istruzione if dovrà corrispondere a "contiene" e non a "esclude".

var contains = /abc/;
var excludes =/hede/;

if(string.match(contains) && !(string.match(excludes))){  //proceed...

Credo che i progettisti di RegEx abbiano anticipato l'uso di non operatori.

BrunoFacca Apr 26 2018 at 01:15

Forse lo troverai su Google mentre provi a scrivere una regex in grado di abbinare segmenti di una riga (anziché intere righe) che non contengono una sottostringa. Mi hai chiesto un po 'di capire, quindi condividerò:

Data una stringa: <span class="good">bar</span><span class="bad">foo</span><span class="ugly">baz</span>

Voglio abbinare i <span>tag che non contengono la sottostringa "bad".

/<span(?:(?!bad).)*?>corrisponderà a <span class=\"good\">e <span class=\"ugly\">.

Notare che ci sono due gruppi (livelli) di parentesi:

  • Quello più interno è per il lookahead negativo (non è un gruppo di cattura)
  • Il più esterno è stato interpretato da Ruby come gruppo di cattura ma non vogliamo che sia un gruppo di cattura, quindi ho aggiunto?: All'inizio è e non è più interpretato come un gruppo di cattura.

Demo in Ruby:

s = '<span class="good">bar</span><span class="bad">foo</span><span class="ugly">baz</span>'
s.scan(/<span(?:(?!bad).)*?>/)
# => ["<span class=\"good\">", "<span class=\"ugly\">"]