5431 Stimmen

Regulärer Ausdruck, um eine Zeile zu finden, die kein Wort enthält

Ich weiß, dass es möglich ist, ein Wort abzugleichen und dann die Übereinstimmungen mit anderen Tools umzukehren (z. B. grep -v). Ist es jedoch möglich, Zeilen abzugleichen, die kein bestimmtes Wort enthalten, z. B. hede, unter Verwendung eines regulären Ausdrucks?

Eingabe:
hoho
hihi
haha
hede
Code:
grep "" input
Gewünschte Ausgabe:
hoho
hihi
haha

108 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.

441 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.

6voto

Anas R. Punkte 357

Solange Sie es mit Zeilen zu tun haben, markieren Sie einfach die negativen Treffer und zielen auf den Rest ab.

Tatsächlich verwende ich diesen Trick mit sed, weil ^((?!hede).)*$ von ihm nicht unterstützt wird.

Für die gewünschte Ausgabe

  1. Markieren Sie den negativen Treffer: (z.B. Zeilen mit hede), indem Sie ein Zeichen verwenden, das im gesamten Text überhaupt nicht enthalten ist. Ein Emoji könnte für diesen Zweck wahrscheinlich eine gute Wahl sein.

    s/(.*hede)/\1/g
  2. Zielen Sie auf den Rest ab (die unmarkierten Zeichenfolgen: z.B. Zeilen ohne hede). Nehmen wir an, Sie möchten nur das Ziel behalten und den Rest löschen (wie Sie es möchten):

    s/^.*//g

Für ein besseres Verständnis

Nehmen wir an, Sie möchten das Ziel löschen:

  1. Markieren Sie den negativen Treffer: (z.B. Zeilen mit hede), indem Sie ein Zeichen verwenden, das im gesamten Text überhaupt nicht enthalten ist. Ein Emoji könnte für diesen Zweck wahrscheinlich eine gute Wahl sein.

    s/(.*hede)/\1/g
  2. Zielen Sie auf den Rest ab (die unmarkierten Zeichenfolgen: z.B. Zeilen ohne hede). Nehmen wir an, Sie möchten das Ziel löschen:

    s/^[^].*//g
  3. Entfernen Sie die Markierung:

    s///g

5voto

^((?!hede).)*$ ist eine elegante Lösung, außer dass sie Zeichen verbraucht, sodass Sie sie nicht mit anderen Kriterien kombinieren können. Angenommen, Sie möchten beispielsweise das Nicht-Vorkommen von "hede" und das Vorkommen von "haha" überprüfen. Diese Lösung würde funktionieren, weil sie keine Zeichen verbraucht:

^(?!.*\bhede\b)(?=.*\bhaha\b)

3voto

JohnP2 Punkte 1711

Eine einfachere Lösung besteht darin, den Not-Operator ! zu verwenden.

Ihre if-Anweisung muss "enthält" übereinstimmen und nicht "ausgeschlossen" übereinstimmen.

var contains = /abc/;
var excludes =/hede/;

if(string.match(contains) && !(string.match(excludes))){  //fortfahren...

Ich glaube, die Designer von RegEx haben die Verwendung von Not-Operatoren vorgesehen.

3voto

jaytea Punkte 1721

So verwenden Sie PCRE's Backtracking-Steuerungsverben, um eine Zeile ohne ein Wort abzugleichen

Hier ist eine Methode, die ich noch nicht gesehen habe:

/.*hede(*COMMIT)^|/

Wie es funktioniert

Zuerst versucht es, "hede" irgendwo in der Zeile zu finden. Wenn erfolgreich, sagt (*COMMIT) dem Motor, nicht nur im Falle eines Fehlers nicht zurückzuverfolgen, sondern auch keine weiteren Übereinstimmungen in diesem Fall zu versuchen. Dann versuchen wir, etwas abzugleichen, das unmöglich übereinstimmen kann (in diesem Fall ^).

Wenn eine Zeile "hede" nicht enthält, trifft die zweite Alternative, ein leeres Teilmuster, erfolgreich auf den Zeichenfolge zu.

Diese Methode ist nicht effizienter als ein negativer Ausblick, aber ich dachte, ich werde sie hier einfach hinschmeißen, falls jemand sie hübsch findet und eine Verwendung dafür in anderen, interessanteren Anwendungen findet.

3voto

BrunoF Punkte 2833

Vielleicht finden Sie das auf Google, während Sie versuchen, einen Regex zu schreiben, der in der Lage ist, Segmente einer Zeile (im Gegensatz zu ganzen Zeilen) zu finden, die nicht einen bestimmten Teilstring enthalten. Es hat eine Weile gedauert, bis ich das herausgefunden habe, also teile ich es:

Gegeben sei ein String:

barfoobaz

Ich möchte Tags finden, die den Teilstring "bad" nicht enthalten.

/ wird und finden.

Beachten Sie, dass es zwei Sätze (Schichten) von Klammern gibt:

  • Die innerste ist für das Negative Lookahead (es ist keine Erfassungsgruppe)
  • Die äußerste wurde von Ruby als Erfassungsgruppe interpretiert, aber wir wollen nicht, dass sie erfasst wird, also habe ich ein ?: am Anfang hinzugefügt und sie wird nicht mehr als Erfassungsgruppe interpretiert.

Demo in Ruby:

s = 'barfoobaz'
s.scan(//)
# => ["", ""]

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X