it-swarm.com.de

Wie negiere ich ein bestimmtes Wort in Regex?

Ich weiß, dass ich eine Gruppe von Zeichen wie in [^bar] Negieren kann, aber ich brauche einen regulären Ausdruck, in dem die Negation auf das bestimmte Wort zutrifft - also wie negiere ich in meinem Beispiel ein tatsächliches "bar" Und nicht "any chars in bar"?

565
Bostone

Ein guter Weg, dies zu tun, ist negativer Lookahead :

^(?!.*bar).*$

Das negative Lookahead-Konstrukt ist das Klammerpaar, wobei auf die öffnende Klammer ein Fragezeichen und ein Ausrufezeichen folgen. Im Lookahead [ist ein beliebiges Regex-Muster].

625

Wenn die Leistung nicht von größter Bedeutung ist, ist es oft einfacher, die Ergebnisse in einem zweiten Durchgang zu analysieren und dabei diejenigen zu überspringen, die den zu negierenden Wörtern entsprechen.

Reguläre Ausdrücke bedeuten in der Regel, dass Sie Skripte oder eine Aufgabe mit geringer Leistung ausführen. Suchen Sie daher nach einer Lösung, die einfach zu lesen, zu verstehen und zu warten ist.

59
Bryan Oakley

Der folgende reguläre Ausdruck wird das tun, was Sie wollen (solange negative Lookbehinds und Lookaheads unterstützt werden), und die Dinge richtig zuordnen. Das einzige Problem ist, dass es mit einzelnen Zeichen übereinstimmt (d. h. jede Übereinstimmung ist ein einzelnes Zeichen anstatt mit allen Zeichen zwischen zwei aufeinanderfolgenden "Strichen"), was möglicherweise zu einem hohen Overhead führt, wenn Sie mit sehr langen Zeichenfolgen arbeiten.

b(?!ar)|(?<!b)a|a(?!r)|(?<!ba)r|[^bar]
44
JAB

Sie können entweder einen negativen Look-Ahead oder einen Look-Behind verwenden:

^(?!.*?bar).*
^(.(?<!bar))*?$

Oder verwenden Sie nur die Grundlagen:

^(?:[^b]+|b(?:$|[^a]|a(?:$|[^r])))*$

Diese passen alle zu allem, was bar nicht enthält.

42
Gumbo

Ich bin auf diesen Forenthread gestoßen, als ich versucht habe, einen regulären Ausdruck für die folgende englische Aussage zu finden:

Bei einer gegebenen Eingabezeichenfolge stimmen Sie mit alles überein, es sei denn , diese Eingabezeichenfolge ist genau 'bar'; Zum Beispiel möchte ich "Barrier" und "Disbar" sowie "Foo" entsprechen.

Hier ist der Regex, den ich mir ausgedacht habe

^(bar.+|(?!bar).*)$

Meine englische Übersetzung des regulären Ausdrucks lautet "Entspricht der Zeichenfolge, wenn sie mit" bar "beginnt und mindestens ein anderes Zeichen enthält oder wenn die Zeichenfolge nicht mit" bar "beginnt.

30

Lösung:

^(?!.*STRING1|.*STRING2|.*STRING3).*$

xxxxxx OK

xxxSTRING1xxx KO (ist, ob es gewünscht ist)

xxxSTRING2xxx KO (ist, ob es gewünscht ist)

xxxSTRING3xxx KO (ist, ob es gewünscht ist)

28
sgrillon

Die akzeptierte Antwort lautet Nice, ist jedoch eine Umgehungslösung für das Fehlen eines einfachen Negationsoperators für Unterausdrücke in regulären Ausdrücken. Aus diesem Grund wird grep --invert-match beendet. In * nixes können Sie das gewünschte Ergebnis mit Pipes und einem zweiten regulären Ausdruck erzielen.

grep 'something I want' | grep --invert-match 'but not these ones'

Immer noch ein Workaround, aber vielleicht leichter zu merken.

9
Greg Bell

Ich möchte die akzeptierte Antwort ergänzen und mit meiner späten Antwort zur Diskussion beitragen.

@ChrisVanOpstal hat dieses Regex-Tutorial geteilt. Dies ist eine großartige Ressource zum Erlernen von Regex.

Das Durchlesen war jedoch sehr zeitaufwändig.

Ich habe einen Spickzettel zur Gedächtnisstütze gemacht.

Diese Referenz basiert auf den geschweiften Klammern [], () und {}, die jede Klasse anführen, und ich kann mich leicht daran erinnern.

Regex = {
 'single_character': ['[]', '.', {'negate':'^'}],
 'capturing_group' : ['()', '|', '\\', 'backreferences and named group'],
 'repetition'      : ['{}', '*', '+', '?', 'greedy v.s. lazy'],
 'anchor'          : ['^', '\b', '$'],
 'non_printable'   : ['\n', '\t', '\r', '\f', '\v'],
 'shorthand'       : ['\d', '\w', '\s'],
 }
3
Algebra

Ich hatte eine Liste von Dateinamen, und ich wollte bestimmte mit dieser Art von Verhalten (Ruby) ausschließen:

files = [
  'mydir/states.rb',      # don't match these
  'countries.rb',
  'mydir/states_bkp.rb',  # match these
  'mydir/city_states.rb' 
]
excluded = ['states', 'countries']

# set my_rgx here

result = WankyAPI.filter(files, my_rgx)  # I didn't write WankyAPI...
assert result == ['mydir/city_states.rb', 'mydir/states_bkp.rb']

Hier ist meine Lösung:

excluded_rgx = excluded.map{|e| e+'\.'}.join('|')
my_rgx = /(^|\/)((?!#{excluded_rgx})[^\.\/]*)\.rb$/

Meine Annahmen für diese Anwendung:

  • Die auszuschließende Zeichenfolge befindet sich am Anfang der Eingabe oder unmittelbar nach einem Schrägstrich.
  • Die zulässigen Zeichenfolgen enden mit .rb.
  • Zulässige Dateinamen haben kein . -Zeichen vor dem .rb.
1

Ich dachte nur an etwas anderes, das getan werden könnte. Es unterscheidet sich sehr von meiner ersten Antwort, da es keine regulären Ausdrücke verwendet, und ich habe mich entschlossen, einen zweiten Antwortbeitrag zu verfassen.

Verwenden Sie die Methode split() der Sprache Ihrer Wahl, die für die Zeichenfolge mit dem Wort äquivalent ist, um als Argument für die Aufteilung zu negieren. Ein Beispiel mit Python:

>>> text = 'barbarasdbarbar 1234egb ar bar32 sdfbaraadf'
>>> text.split('bar')
['', '', 'asd', '', ' 1234egb ar ', '32 sdf', 'aadf']

Das Schöne daran, es so zu machen, zumindest in Python (ich erinnere mich nicht, ob die Funktionalität beispielsweise in Visual Basic oder Java gleich wäre), ist, dass Sie indirekt wissen, wann "bar" wurde in der Zeichenfolge wiederholt, da die leeren Zeichenfolgen zwischen "bar" in der Ergebnisliste enthalten sind (obwohl die leere Zeichenfolge am Anfang darauf zurückzuführen ist, dass am Anfang der Zeichenfolge ein "bar" steht Zeichenfolge). Wenn Sie das nicht möchten, können Sie einfach die leeren Zeichenfolgen aus der Liste entfernen.

1
JAB

Auszug aus dieser Kommentar von bkDJ :

^(?!bar$).*

Das Schöne an dieser Lösung ist, dass es möglich ist, mehrere Wörter eindeutig zu negieren (auszuschließen):

^(?!bar$|foo$|banana$).*
0
leventov