Domanda

Alla ricerca di un po 'di aiuto regex. Vorrei progettare un'espressione che corrisponda a una stringa con " pippo " OPPURE " barra " ;, ma non entrambi " pippo " E " barra "

Se faccio qualcosa come ...

/((foo)|(bar))/

Corrisponderà a " foobar " ;. Non è quello che sto cercando. Quindi, come posso far corrispondere regex solo quando è presente un termine o l'altro?

Grazie!

È stato utile?

Soluzione

Puoi farlo con una sola regex ma ti suggerisco per motivi di leggibilità di fare qualcosa come ...

(/foo/ and not /bar/) || (/bar/ and not /foo/)

Altri suggerimenti

Questo è quello che uso:

/^(foo|bar){1}$/

Vedi: http://www.regular-expressions.info/quickstart.html sotto ripetizione

Se il tuo linguaggio regex lo supporta, usa sguardo negativo :

(?<!foo|bar)(foo|bar)(?!foo|bar)

Questo corrisponderà a " foo " o "barra" che non è immediatamente preceduto o seguito da "pippo". o "bar", che penso sia quello che volevi.

Non è chiaro dalla tua domanda o dai tuoi esempi se la stringa che stai cercando di abbinare può contenere altri token: " foocuzbar " ;. In tal caso, questo modello non funzionerà.

Ecco i risultati dei tuoi casi di test (" true " significa che il modello è stato trovato nell'input):

foo: true
bar: true
foofoo: false
barfoo: false
foobarfoo: false
barbar: false
barfoofoo: false

Questo richiederà 'foo' e 'bar' ma non 'foobar' e non 'blafoo' e non 'blabar':

/^(foo|bar)$/

^ = mark start of string (or line)
$ = mark end of string (or line)

Questo richiederà 'foo' e 'bar' e 'foo bar' e 'bar-foo' ma non 'foobar' e non 'blafoo' e non 'blabar':

/\b(foo|bar)\b/

\b = mark word boundry

Non hai specificato un comportamento riguardo a contenuti diversi da " foo " e "barra" o ripetizioni di uno in assenza dell'altro. ad esempio, dovrei " pippo d " o " barbar ian " abbinare?

Supponendo che si desideri abbinare stringhe che contengono solo un'istanza di "quotazione" " oppure "barra", ma non entrambe e non più istanze della stessa, indipendentemente da qualsiasi altra cosa nella stringa (ovvero, "cibo" non corrisponde e "barbaro" non corrisponde), è possibile utilizzare un regex che restituisce il numero di corrispondenze trovate e lo considera corretto solo se viene trovata esattamente una corrispondenza. ad es. in Perl:

@matches = ($value =~ /(foo|bar)/g)  # @matches now hold all foos or bars present
if (scalar @matches == 1) {          # exactly one match found
  ...
}

Se sono consentite più ripetizioni dello stesso bersaglio (cioè "corrispondenze" barbariche "), questo stesso approccio generale potrebbe essere utilizzato camminando sull'elenco delle corrispondenze per vedere se le corrispondenze sono tutte ripetizioni dello stesso testo o se è presente anche l'altra opzione.

Potresti prendere in considerazione il? test condizionale.

(?(?=regex)then|else)

Condizioni delle espressioni regolari

Se vuoi una vera esclusiva o, lo farei semplicemente nel codice invece che nella regex. In Perl:

/foo/ xor /bar/

Ma il tuo commento:

  

Corrispondenze: " foo " ;, " bar " nonmatches:   & Quot; foofoo " & Quot; barfoo " & Quot; foobarfoo " & Quot; barbar "   & Quot; barfoofoo "

indica che non stai davvero cercando l'esclusivo o. Intendi davvero " / foo | bar / corrisponde esattamente una volta? "

my $matches = 0;
while (/foo|bar/g) {
  last if ++$matches > 1;
}

my $ok = ($matches == 1)

So che questa è una voce in ritardo, ma solo per aiutare gli altri che potrebbero cercare:

(/b(?:(?:(?!foo)bar)|(?:(?!bar)foo))/b)

Userei qualcosa del genere. Controlla solo lo spazio attorno alle parole, ma potresti usare \ b o \ B per controllare un bordo se usi \ w . Ciò corrisponderebbe a " pippo " o " bar " ;, quindi ovviamente dovresti sostituire anche gli spazi bianchi, per ogni evenienza. (Supponendo che stai sostituendo qualcosa.)

/\s((foo)|(bar))\s/

Non penso che ciò possa essere fatto con una singola espressione regolare. E i confini possono funzionare o meno a seconda di cosa stai confrontando.

Vorrei abbinare ogni regex separatamente, e farei un XOR sui risultati.

foo = re.search("foo", str) != None
bar = re.search("bar", str) != None
if foo ^ bar:
    # do someting...

Ho provato con Regex Coach contro:

x foo y
x bar y
x foobar y

Se seleziono l'opzione g , in effetti corrisponde a tutte e tre le parole, perché cerca di nuovo dopo ogni corrispondenza.
Se non si desidera questo comportamento, è possibile ancorare l'espressione, ad esempio abbinando solo i confini delle parole:

\b(foo|bar)\b

Dare più contesto al problema (come appaiono i dati) potrebbe dare risposte migliori.

\b(foo)\b|\b(bar)\b

E usa solo il primo gruppo di acquisizione .

Usando i confini delle parole, puoi ottenere la singola parola ...

me@home ~  
$ echo "Where is my bar of soap?" | egrep "\bfoo\b|\bbar\b"  
Where is my bar of soap?  

me@home ~  
$ echo "What the foo happened here?" | egrep "\bfoo\b|\bbar\b"  
What the foo happened here?  

me@home ~  
$ echo "Boy, that sure is foobar\!" | egrep "\bfoo\b|\bbar\b"  
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top