Una regex per trovare una sottostringa che non è seguita da un'altra determinata sottostringa


115

Ho bisogno di una regex che corrisponda blahfooblahma nonblahfoobarblah

Voglio che corrisponda solo a foo e tutto intorno a foo, a condizione che non sia seguito da bar.

Ho provato a usare questo: foo.*(?<!bar)che è abbastanza vicino, ma corrisponde blahfoobarblah. Lo sguardo negativo dietro deve corrispondere a qualsiasi cosa e non solo al bar.

Il linguaggio specifico che sto usando è Clojure che utilizza regex Java sotto il cofano.

EDIT: Più specificamente, ho anche bisogno che passi blahfooblahfoobarblahma non blahfoobarblahblah.


1
Hai provato a usare foo. * (? <! Bar. *)?
Thibault Falise

Risposte:


158

Provare:

/(?!.*bar)(?=.*foo)^(\w+)$/

test:

blahfooblah            # pass
blahfooblahbarfail     # fail
somethingfoo           # pass
shouldbarfooshouldfail # fail
barfoofail             # fail

Spiegazione delle espressioni regolari

NODE                     EXPLANATION
--------------------------------------------------------------------------------
  (?!                      look ahead to see if there is not:
--------------------------------------------------------------------------------
    .*                       any character except \n (0 or more times
                             (matching the most amount possible))
--------------------------------------------------------------------------------
    bar                      'bar'
--------------------------------------------------------------------------------
  )                        end of look-ahead
--------------------------------------------------------------------------------
  (?=                      look ahead to see if there is:
--------------------------------------------------------------------------------
    .*                       any character except \n (0 or more times
                             (matching the most amount possible))
--------------------------------------------------------------------------------
    foo                      'foo'
--------------------------------------------------------------------------------
  )                        end of look-ahead
--------------------------------------------------------------------------------
  ^                        the beginning of the string
--------------------------------------------------------------------------------
  (                        group and capture to \1:
--------------------------------------------------------------------------------
    \w+                      word characters (a-z, A-Z, 0-9, _) (1 or
                             more times (matching the most amount
                             possible))
--------------------------------------------------------------------------------
  )                        end of \1
--------------------------------------------------------------------------------
  $                        before an optional \n, and the end of the
                           string

Altre espressioni regolari

Se vuoi escludere solo barquando è subito dopo foo, puoi usare

/(?!.*foobar)(?=.*foo)^(\w+)$/

modificare

Hai aggiornato la tua domanda per renderla specifica.

/(?=.*foo(?!bar))^(\w+)$/

Nuovi test

fooshouldbarpass               # pass
butnotfoobarfail               # fail
fooshouldpassevenwithfoobar    # pass
nofuuhere                      # fail

Nuova spiegazione

(?=.*foo(?!bar))assicura che foovenga trovato ma non seguito direttamentebar


Questo è molto vicino e un'ottima risposta. Sapevo che non sarei stato abbastanza specifico. :( Ho bisogno di questo: "blahfoomeowwoof / foobar /" per passare a causa del solitario "foo", ma non questo blahfoobarmeowwoof Se è possibile.
Rayne

Come domanda a margine, come si fa ad abbinare qualcosa come "bot" ma non "botters"?
Rayne

Sì. Posso usare quello che ho adesso, ma sarebbe più facile se potessi abbinare solo bot ma non botter. Mi dispiace molto. Non ho esperienza con le regex e temo di capire lentamente cosa voglio da solo. : p
Rayne

1
@ Rayne, questa è la stessa domanda. Nel tuo esempio sopra, volevi abbinare fooma non foobar. Per abbinare botma non botters, useresti /(?=.*bot(?!ters))^(\w+)$/.
maček

Bene, in genere miravo a parole intere. Come ho detto, sono confuso su ciò che voglio veramente e su ciò che è davvero possibile. Farlo in questo modo funzionerà. Grazie per il tempo. :)
Rayne

55

Per abbinare un fooseguito con qualcosa che non inizia con bar, prova

foo(?!bar)

La tua versione con lookbehind negativo è effettivamente "abbina una fooseguita da qualcosa che non finisce in bar". Le .*corrispondenze tutte barblah, e le (?<!bar)guardano indietro lahe verificano che non corrispondano bar, cosa che non è, quindi l'intero schema corrisponde.


Quindi l'ho provato per un'espressione regolare progettata per abbinare la stringa "did you" purché non sia seguita da "say". Funziona quando la differenza tra "hai detto" e "hai pensato", per esempio, ma solo "hai fatto" di per sé non viene catturato, e dovrebbe. Eventuali suggerimenti?
soosus

2

Usa invece uno sguardo negativo al futuro:

\s*(?!\w*(bar)\w*)\w*(foo)\w*\s*

Questo ha funzionato per me, spero che aiuti. In bocca al lupo!


Regex semplice ma efficace, che funziona anche per escludere le stringhe ripetute ("foofoo"). Perfetto!
Jonas Byström

1

Hai scritto un commento suggerendo che ti piace questo per lavorare abbinando tutte le parole in una stringa anziché l'intera stringa stessa.

Piuttosto che schiacciare tutto questo in un commento, lo sto postando come una nuova risposta.

Nuovo Regex

/(?=\w*foo(?!bar))(\w+)/

Testo di esempio

foowithbar fooevenwithfoobar notfoobar foohere notfoobarhere butfooisokherebar notfoobarhere andnofuu needsfoo

fiammiferi

foowithbar fooevenwithfoobar foohere butfooisokherebar needsfoo


0

La tua richiesta di corrispondenza specifica può essere soddisfatta da:

\w+foo(?!bar)\w+

Questo corrisponderà blahfooblahfoobarblahma non blahfoobarblahblah.

Il problema con la tua regex di foo.*(?<!bar)è il .*dopo foo. Corrisponde a tutti i caratteri inclusi i caratteri successivi bar.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.