Domanda

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 es. hede, usando un'espressione regolare?

ingresso:

hoho
hihi
haha
hede

Codice:

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

Uscita desiderata:

hoho
hihi
haha
È stato utile?

Soluzione

L'idea che regex non supporti la corrispondenza inversa non è del tutto vera. Puoi imitare questo comportamento usando gli sguardi negativi:

^((?!hede).)*$

La regex sopra corrisponderà a qualsiasi stringa o riga senza interruzione di riga, non contenente la (sotto) stringa 'hede'. Come accennato, questo non è qualcosa che regex è & Quot; buono & Quot; at (o dovrebbe fare), ma è ancora possibile .

E se devi abbinare anche i caratteri di interruzione di riga, utilizza il modificatore DOT-ALL (il s finale nel seguente schema):

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

o usalo in linea:

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

(dove /.../ sono i delimitatori regex, ovvero non parte del modello)

Se il modificatore DOT-ALL non è disponibile, è possibile imitare lo stesso comportamento con la classe di caratteri [\s\S]:

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

Spiegazione

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

    ┌──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┐
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 (?!hede). sono le stringhe vuote. La regex "hede" guarda avanti per vedere se non c'è alcuna sottostringa . da vedere, e se questo è il caso (quindi si vede qualcos'altro), allora il ((?!hede).)* (punto) corrisponderà a qualsiasi carattere tranne un'interruzione di riga . I look-around sono anche chiamati asserzioni di larghezza zero perché non consumano alcun personaggio. Asseriscono / convalidano solo qualcosa.

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

Come puoi vedere, l'ingresso <=> fallirà perché su <=>, la regex <=> fallisce (lì è <=> avanti!).

Altri suggerimenti

Nota che la soluzione per non inizia con & # 8220; hede & # 8221; :

^(?!hede).*$

è generalmente molto più efficiente della soluzione a non contiene & # 8220; hede & # 8221; :

^((?!hede).)*$

Il primo controlla & # 8220; hede & # 8221; solo nella prima stringa di input & # 8217; s, anziché in ogni posizione.

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

ETA Oh, rileggendo la domanda, grep -v è probabilmente quello che intendevi con " opzioni strumenti " ;.

Risposta:

^((?!hede).)*$

Spiegazione:

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

hede la tua stringa,

) fine della ricerca, . qualsiasi carattere tranne \ n,
)* fine di \ 1 (Nota: poiché si sta utilizzando un quantificatore in questa acquisizione, solo l'ULTIMA ripetizione del modello acquisito verrà archiviata in \ 1)
$ prima di un \ n facoltativo e la fine della stringa

Le risposte fornite sono perfettamente valide, solo un punto accademico:

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

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

Fa solo una corrispondenza COMPLETA. Farlo per le partite secondarie sarebbe persino più imbarazzante.

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

^(?!hede$).*

es. - Se si desidera consentire tutti i valori tranne & Quot; foo & Quot; (cioè " foofoo " ;, " barfoo " ;, e " foobar " passerà, ma " foo quot; fallirà), utilizzare: ^(?!foo$).*

Naturalmente, se stai controllando l'uguaglianza esatta , una soluzione generale migliore in questo caso è quella di verificare l'uguaglianza delle stringhe, cioè

myStr !== 'foo'

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

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

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

FWIW, poiché le lingue regolari (ovvero le lingue razionali) sono chiuse in modo complementare, è sempre possibile trovare un'espressione regolare (aka espressione razionale) che nega un'altra espressione. Ma non molti strumenti implementano questo.

Vcsn supporta questo operatore (che indica {c}, postfix ).

Definisci innanzitutto il tipo di espressioni: le etichette sono lettere (lal_char) per scegliere da a a z per esempio (definire l'alfabeto quando si lavora con la complementazione è, ovviamente, molto importante), e il " valore " calcolato per ogni parola è solo un valore booleano: true la 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

 L'automa corrispondente

infine, converte questo automa in una semplice espressione.

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

dove + è generalmente indicato |, \e indica la parola vuota e [^] è solitamente 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 prova Vcsn online .

Ecco una buona spiegazione del perché non è facile negare una regex arbitraria. Devo concordare con le altre risposte, però: se questa è qualcosa di diverso da una domanda ipotetica, allora una regex non è la scelta giusta qui.

Con lookahead negativo, l'espressione regolare può corrispondere a qualcosa che non contiene un modello specifico. Questa è la risposta e spiegata da Bart Kiers. Grande spiegazione!

Tuttavia, con la risposta di Bart Kiers, la parte lookahead metterà alla prova da 1 a 4 caratteri mentre si abbina un singolo personaggio. Possiamo evitarlo e lasciare che la parte lookahead verifichi l'intero testo, assicurandoci che non ci sia 'hede', e quindi la parte normale (. *) Può mangiare l'intero testo in una sola volta.

Ecco la regex migliorata:

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

Nota che il quantificatore (*?) pigro nella parte negativa del lookahead è facoltativo, puoi invece usare (*) il quantificatore avido, a seconda dei tuoi dati: se 'hede' è presente e nella metà iniziale del testo, il 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 e Lookbehind .

Inoltre, controlla RegexGen.js , un generatore di espressioni regolari JavaScript che aiuta a costruire espressioni regolari complesse. Con RegexGen.js, puoi costruire il 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()
);

Benchmarks

Ho deciso di valutare alcune delle Opzioni presentate e 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 devono corrispondere, poiché contengono l'espressione cercata, mentre le 7 righe inferiori devono 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 corse - Numero più grande = 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

Dato che .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 certe parole. Ad esempio, se le prime due lettere della stringa di ricerca non sono uguali, la risposta 03 può essere espansa in ^(?>[^R]+|R+(?!egex Hero))*$ con conseguente piccolo guadagno di prestazione.

Ma la soluzione complessiva più leggibile e più veloce in termini di prestazioni sembra essere 05 usando un'istruzione condizionale o 04 con il quantificatore possessivo. Penso che le soluzioni Perl dovrebbero essere ancora più veloci e più facilmente leggibili.

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

ad es. 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 grep seriale è (non un commento) e (corrisponde a dir)

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))*$/

Il sopra menzionato (?:(?!hede).)* è fantastico 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:

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

Questa semplificazione è pronta per avere " AND " clausole aggiunte:

^(?!.*hede)(?=.*foo)(?=.*bar)   # A line with foo and bar, but without hede
^(?!.*hede)(?=.*foo).*bar       # Same

Ecco come lo farei:

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

Accurato e più efficiente delle altre risposte. Implementa la tecnica di efficienza & Quot; unrolling-the-loop & Quot; e richiede molto meno backtracking.

Se si desidera abbinare un personaggio per negare una parola simile a negare la classe di caratteri:

Ad esempio, una stringa:

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

Non utilizzare:

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

Usa:

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

Nota "(?!bbb)." non è né lookbehind né lookahead, è lookcurrent, ad esempio:

"(?=abc)abcde", "(?!abc)abcde"

L'OP non ha specificato o Tag il post per indicare il contesto (linguaggio di programmazione, editor, strumento) all'interno del quale verrà utilizzato Regex.

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

hede supporta Regex, ma non supporta lookahead o lookbehind, quindi sono necessari alcuni passaggi.

Se sto cercando di conservare tutte le righe che NON contengono la stringa <=> , lo farei così:

  

1. Cerca / sostituisci l'intero file per aggiungere un unico & Quot; Tag & Quot; 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 <=> (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 <=> . Rimuovi la & Quot unica; Tag & Quot; 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 <=> rimossa.


Se sto cercando Do Something Else solo per le righe che NON contengono la stringa <=> , lo farei così:

  

1. Cerca / sostituisci l'intero file per aggiungere un unico & Quot; Tag & Quot; all'inizio di ogni riga contenente qualsiasi testo.

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

2. Per tutte le righe che contengono la stringa <=> , rimuovi l'esclusivo & Quot; Tag & Quot ;:

<*>

  

3. A questo punto, tutte le righe che iniziano con l'esclusivo & Quot; Tag & Quot ;, NON contengono la stringa <=> . Ora posso fare il mio Qualcos'altro solo per quelle righe.

  

4. Quando ho finito, rimuovo l'esclusivo & Quot; Tag & Quot; da tutte le righe (la stringa di sostituzione è vuota):

<*>

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

^(?!.*hede)

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

Naturalmente, è possibile avere più requisiti di errore:

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

Dettagli: l'ancora ^ assicura che il motore regex non tenti di ripetere la corrispondenza in ogni posizione della stringa, che corrisponderebbe a ogni stringa.

L'ancora ^ all'inizio è pensata per rappresentare l'inizio della linea. Lo strumento grep fa corrispondere ciascuna riga una alla volta, nei contesti in cui lavori con una stringa multilinea, puoi usare & Quot; m & Quot; Bandiera:

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

o

(?m)^(?!.*hede) # Inline flag

Dall'introduzione di ruby-2.4.1, possiamo usare il nuovo Operatore assente in Ruby & # 8217; s Espressioni regolari

dal doc

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

Pertanto, 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"]

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

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

Questo salta completamente la riga che contiene la stringa esatta hede e corrisponde a tutte le righe rimanenti.

DEMO

Esecuzione delle parti:

Consideriamo la regex sopra divisa in due parti.

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

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

    ^.*$
    

PARTE 1

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

<*>

Spiegazione:

  • $ Afferma che siamo all'inizio.
  • (*F) Corrisponde alla stringa (*FAIL)
  • .* Asserisce che siamo alla fine della linea.

Quindi la riga che contiene la stringa . verrebbe abbinata. Quando il motore regex vede il seguente * ( Nota: puoi scrivere .+ come <=> ) verbo, salta e fa fallire la corrispondenza. <=> chiamato alterazione o operatore logico OR aggiunto accanto al verbo PCRE che inturn corrisponde a tutti i confini esistenti tra ogni singolo carattere su tutte le righe tranne la riga contiene la stringa esatta <=>. Guarda la demo qui . Cioè, cerca di abbinare i caratteri della stringa rimanente. Ora la regex nella seconda parte verrebbe eseguita.

PARTE 2

<*>

Spiegazione:

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

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

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

  • <=> Qui non è necessaria la fine della linea di ancoraggio.

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 \| deve funzionare solo con Espressioni regolari di base , che semplicemente non sono abbastanza potenti per eseguire tale compito (non sono in grado di analizzare le lingue regolari, a causa della mancanza di alternanza e raggruppamento).

Tuttavia, GNU \( implementa estensioni che lo consentono. In particolare, \) è l'operatore di alternanza nell'implementazione di BRE di GNU e egrep e testinput.txt sono gli operatori di raggruppamento. Se il tuo motore di espressioni regolari supporta l'alternanza, le espressioni di parentesi negative, il raggruppamento e la stella di Kleene ed è in grado di ancorare all'inizio e alla fine della stringa, questo è tutto ciò di cui hai bisogno per questo approccio.

Con GNU hede, sarebbe qualcosa del tipo:

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

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

Puoi anche utilizzare uno strumento che implementa Espressioni regolari estese , come <=>, per eliminare le 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 <=> nella directory corrente):

#!/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 coloro che sono interessati ai dettagli, la tecnica utilizzata è quella di 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, quindi convertendo il risultante FA torna a un'espressione regolare.

Infine, come tutti hanno notato, se il tuo motore di espressioni regolari supporta lookahead negativo, questo semplifica molto l'attività. Ad esempio, con GNU grep:

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

Aggiornamento: di recente ho trovato l'eccellente libreria , scritto in PHP, che fornisce una funzionalità simile a Grail. Usandolo e un semplificatore scritto da me stesso, sono stato in grado di scrivere un generatore online di espressioni regolari negative con una frase di input (solo caratteri alfanumerici e spaziali attualmente supportati): http://www.formauri.es/personal/pgimeno/misc/non-match-regex/

Per <=> genera:

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

che equivale a quanto sopra.

Potrebbe essere più gestibile per due regex nel codice, uno per eseguire la prima corrispondenza, e quindi se corrisponde eseguire la seconda regex per verificare casi anomali che si desidera bloccare, ad esempio ^.*(hede).*, disporre di una logica appropriata in il tuo codice.

OK, ammetto che questa non è in realtà una risposta alla domanda postata e potrebbe anche usare un po 'più di elaborazione di una singola regex. Ma per gli sviluppatori che sono venuti qui alla ricerca di una rapida soluzione di emergenza per un caso anomalo, questa soluzione non deve essere trascurata.

La Lingua TXR supporta la negazione regex.

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

Un esempio più complicato: abbina tutte le righe che iniziano con a e terminano 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 di Regex non è particolarmente utile da sola, ma quando hai anche un incrocio, le cose diventano interessanti, dato che hai un set completo di operazioni booleane: puoi esprimere " l'insieme che corrisponde a questo, tranne che per cose che corrispondono a " ;.

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;
    }


?>

Come usare i verbi di controllo di backtracking di PCRE per abbinare una riga che non contiene una parola

Ecco un metodo che non avevo mai visto usato prima:

/.*hede(*COMMIT)^|/

Come funziona

Per prima cosa, cerca di trovare " hede " da qualche parte nella linea. In caso di successo, a questo punto, (*COMMIT) indica al motore di non solo tornare indietro in caso di guasto, ma anche di non tentare ulteriori corrispondenze in quel caso. Quindi, proviamo ad abbinare qualcosa che non può corrispondere (in questo caso, ^).

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

Questo metodo non è più efficiente di uno sguardo negativo, ma ho pensato di buttarlo qui nel caso in cui qualcuno lo trovasse elegante e ne trovasse un uso per altre applicazioni più interessanti.

Forse lo troverai su Google mentre provi a scrivere una regex in grado di abbinare segmenti di una linea (al contrario di intere linee) che non contengono una sottostringa. Mi ci è voluto un po 'per capire, quindi condividerò:

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

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

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

Si noti che esistono due serie (livelli) di parentesi:

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

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\">"]

Una soluzione più semplice consiste nell'utilizzare l'operatore non !

L'istruzione if dovrà corrispondere a " contiene " e non corrisponde 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.

Con ConyEdit , puoi utilizzare la riga di comando cc.gl !/hede/ per ottenere linee che non contengono regex corrispondenza o utilizzare la riga di comando cc.dl /hede/ per eliminare le righe che contengono la corrispondenza regex. Hanno lo stesso risultato.

^ ((?! hede).) * $ è una soluzione elegante, tranne perché consuma caratteri che non potrai combinare con altri criteri. Ad esempio, supponiamo che tu voglia verificare la non presenza di & Quot; hede & Quot; e la presenza di " haha. " Questa soluzione funzionerebbe perché non consumerebbe caratteri:

^ (?!. \ bhede \ b) (? =. \ bhaha \ b)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top