Die Vorstellung, dass Regex das inverse Matchen nicht unterstützt, ist nicht ganz richtig. Sie können dieses Verhalten nachahmen, indem Sie negative Look-arounds verwenden:
^((?!hede).)*$
Das obige Regex wird auf jede Zeichenkette oder Zeile ohne Zeilenumbruch passen, die das (Teil-)Zeichen 'hede' nicht enthält. Wie bereits erwähnt, ist dies nicht etwas, was Regex "gut" kann (oder tun sollte), aber es ist dennoch möglich.
Und wenn Sie auch Zeilenumbruchzeichen passen müssen, verwenden Sie den DOT-ALL Modifier (das abschließende s
im folgenden Muster):
/^((?!hede).)*$/s
oder verwenden Sie es inline:
/(?s)^((?!hede).)*$/
(wobei die /.../
die Regex-Trennzeichen sind, also nicht Teil des Musters)
Wenn der DOT-ALL Modifier nicht verfügbar ist, können Sie das gleiche Verhalten mit der Zeichenklasse [\s\S]
nachahmen:
/^((?!hede)[\s\S])*$/
Erklärung
Eine Zeichenkette ist einfach eine Liste von n
Zeichen. Vor und nach jedem Zeichen gibt es eine leere Zeichenkette. Daher wird eine Liste von n
Zeichen n+1
leere Zeichenketten haben. Betrachten Sie die Zeichenkette "ABhedeCD"
:
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
wo die e
's die leeren Zeichenketten sind. Das Regex (?!hede).
schaut voraus, um zu sehen, ob die Teilzeichenkette "hede"
nicht zu sehen ist, und wenn das der Fall ist (also etwas anderes zu sehen ist), dann wird der Punkt .
auf jedes Zeichen außer einem Zeilenumbruch passen. Look-arounds werden auch als Zero-Width-Assertions bezeichnet, weil sie keine Zeichen verbrauchen. Sie bestätigen/validieren nur etwas.
Also werden in meinem Beispiel zunächst alle leeren Zeichenketten validiert, um zu sehen, ob vor dem Verzehren eines Zeichens kein "hede"
voraus ist, bevor der Punkt .
(dot) auf ein Zeichen passt. Das Regex (?!hede).
wird das nur einmal tun, daher ist es in einer Gruppe eingeschlossen und wird null oder mehrmals wiederholt: ((?!hede).)*
. Schließlich sind der Anfang und das Ende der Eingabe verankert, um sicherzustellen, dass die gesamte Eingabe verbraucht wird: ^((?!hede).)*$
Wie Sie sehen können, wird die Eingabe "ABhedeCD"
scheitern, weil beim e3
das Regex (?!hede)
scheitert (da tatsächlich "hede"
voraus ist!).
105 Stimmen
Wahrscheinlich ein paar Jahre zu spät, aber was ist falsch mit:
([^h]*(h([^e]|$)|he([^d]|$)|hed([^e]|$)))*
? Die Idee ist einfach. Fahren Sie mit dem Abgleich fort, bis Sie den Beginn des unerwünschten Strings sehen, und gleichen Sie dann nur in den N-1 Fällen ab, in denen der String nicht abgeschlossen ist (wobei N die Länge des Strings ist). Diese N-1 Fälle sind "h gefolgt von nicht-e", "he gefolgt von nicht-d" und "hed gefolgt von nicht-e". Wenn es Ihnen gelungen ist, diese N-1 Fälle zu bestehen, haben Sie den unerwünschten String erfolgreich nicht abgeglichen, sodass Sie erneut mit der Suche nach[^h]*
beginnen können.427 Stimmen
@stevendesu: Versuche dies für 'ein-sehr-sehr-langes-Wort' oder noch besser einen halben Satz. Viel Spaß beim Tippen. Übrigens, es ist fast unleserlich. Weiß nicht über den Leistungseinfluss.
14 Stimmen
@PeterSchuetze: Sicher ist es nicht schön für sehr sehr lange Wörter, aber es ist eine praktikable und korrekte Lösung. Obwohl ich keine Tests zur Leistung durchgeführt habe, würde ich mir vorstellen, dass es nicht allzu langsam ist, da die meisten nachfolgenden Regeln ignoriert werden, bis Sie ein h sehen (oder den ersten Buchstaben des Wortes, Satzes usw. sehen). Und Sie könnten den Regex-String für lange Zeichenfolgen leicht mithilfe iterativer Konkatenation generieren. Wenn es funktioniert und schnell generiert werden kann, ist Lesbarkeit wichtig? Dafür sind Kommentare da.
66 Stimmen
@stevendesu: Ich bin noch später dran, aber diese Antwort ist fast komplett falsch. Zum einen verlangt sie, dass das Subjekt "h" enthält, was es nicht sollte, da die Aufgabe lautet, "Zeilen abzugleichen, die ein bestimmtes Wort nicht enthalten". Lassen Sie uns annehmen, dass Sie die innere Gruppe optional machen wollten und dass das Muster verankert ist:
^([^h]*(h([^e]|$)|he([^d]|$)|hed([^e]|$))?)*$
. Dies scheitert, wenn Instanzen von "hede" von teilweisen Instanzen von "hede" wie in "hhede" vorausgehen.19 Stimmen
Diese Frage wurde zum Stack Overflow Regular Expression FAQ hinzugefügt, unter "Advanced Regex-Fu".
0 Stimmen
Verwandt: Regex: Übereinstimmung durch Ausschluss, ohne Vorwärtsblick - ist das möglich?