Frage

Sie suchen ein bisschen regex Hilfe. Ich möchte einen Ausdruck entwerfen, die einen String übereinstimmt mit " foo " oder " bar ", aber nicht beide " foo " AND " bar "

Wenn ich etwas tun, wie ...

/((foo)|(bar))/

Es wird passen " foobar ". Nicht das, was ich suche. Also, wie kann ich Regex machen nur, wenn ein Begriff oder das andere vorhanden ist?

Danke!

War es hilfreich?

Lösung

Sie können mit einem einzigen Regex dies tun, aber ich schlage vor, aus Gründen der Lesbarkeit Sie etwas tun, wie ...

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

Andere Tipps

Dies ist, was ich benutze:

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

Siehe auch: http://www.regular-expressions.info/quickstart.html unter Wiederholung

Wenn Ihre Regex Sprache unterstützt, verwenden Sie negativen Lookarounds :

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

Dies wird „foo“ oder „bar“ übereinstimmen, die von „foo“ oder „bar“ nicht unmittelbar vor- oder nachgeschaltet ist, was ich denke, ist das, was Sie wollten.

Es ist nicht klar, aus Ihrer Frage oder Beispiele, wenn die Zeichenfolge, die Sie anderen Token enthalten übereinstimmen sind versuchen: „foocuzbar“. Wenn ja, wird dieses Muster nicht.

Hier sind die Ergebnisse der Testfälle ( „true“ bedeutet, wurde das Muster in der Eingabe gefunden):

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

Das wird dauern 'foo' und 'bar', aber nicht 'foobar' und nicht 'blafoo' und nicht 'Blåbär':

/^(foo|bar)$/

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

Das wird dauern 'foo' und 'bar' und 'foo bar' und 'Bar-foo', aber nicht 'foobar' und nicht 'blafoo' und nicht 'Blåbär':

/\b(foo|bar)\b/

\b = mark word boundry

Sie haben keine Angabe Verhalten in Bezug auf Inhalte anderer als „foo“ und „bar“ oder Wiederholungen von einem in Abwesenheit des anderen. zum Beispiel sollte " foo d" oder " Barbar ian" Spiel?

Unter der Annahme, dass Sie Strings wollen, die nur eine Instanz für irgendetwas anderes in der Kette von entweder „foo“ oder „bar“, aber nicht beides und nicht mehrere Instanzen der gleichen, ohne Rücksicht enthalten übereinstimmen (dh „Lebensmittel "Begegnungen und‚Barbaren‘stimmen nicht überein), dann könnte man einen regulären Ausdruck verwenden, die die Anzahl von Übereinstimmungen gibt gefunden und nur betrachten es als erfolgreich, wenn genau eine Übereinstimmung gefunden wird. zum Beispiel in Perl:

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

Wenn mehrere Wiederholungen des gleichen Ziels erlaubt sind (dh „Barbaren“ übereinstimmt), dann ist dieser gleiche allgemeine Ansatz verwendet werden könnte, indem dann die Liste der Spiele gehen, um zu sehen, ob die Spiele alle Wiederholungen des gleichen Textes sind, oder wenn die andere Option ist ebenfalls vorhanden.

Sie möchten vielleicht die beachten? bedingter Test.

(?(?=regex)then|else)

Regular Expression Conditionals

Wenn Sie eine echte exklusive oder wollen, würde ich genau das tun in Code statt in der Regex. In Perl:

/foo/ xor /bar/

Aber Ihr Kommentar:

  

Spiele: "foo", "bar" nonmatches:   "Foofoo" "barfoo" "foobarfoo" "Barbar"   "Barfoofoo"

zeigt an, dass Sie nicht wirklich gesuchten exklusiv oder. Sie meinen, eigentlich "Ist genau einmal /foo|bar/ Vorstellungen?"

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

my $ok = ($matches == 1)

Ich weiß, dass dies eine Nachmeldung ist, sondern nur um andere zu helfen, die Suche werden können:

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

würde ich so etwas wie dieses verwenden. Es prüft nur für Raum um die Worte, aber man konnte den \b verwenden oder \B für eine Grenze zu überprüfen, ob Sie \w verwenden. Dies würde „foo“ oder „bar“ entsprechen, so offensichtlich würden Sie auch die Leerzeichen ersetzen müssen, nur für den Fall. (Angenommen, Sie sind alles andere zu ersetzen.)

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

Ich glaube nicht, kann dies mit einem einzigen regulären Ausdruck erfolgen. Und Grenzen können oder auch nicht funktionieren, je nachdem, was Sie passende gegen.

Ich würde separat gegen jede Regex, und auf den Ergebnissen einer XOR tun.

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

Ich habe versucht, mit Regex Coach gegen:

x foo y
x bar y
x foobar y

Wenn ich die g Option ein, in der Tat paßt es alle drei Worte, weil es nach jedem Spiel sucht wieder.
Wenn Sie dieses Verhalten nicht wünschen, können Sie den Ausdruck verankern, zum Beispiel nur an Wortgrenzen passend:

\b(foo|bar)\b

Geben mehr Kontext auf das Problem (was die Daten wie folgt aussieht) könnten bessere Antworten geben.

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

Und nur die erste Capture-Gruppe rel="nofollow.

die Wortgrenzen verwenden, können Sie das Wort bekommen ...

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"  
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top