Wie kann man eine Übereinstimmung mit Regex „invers“ machen?

111

Ich benutze RegexBuddy, aber ich habe trotzdem Probleme mit dieser Sache: \

Ich verarbeite Zeile für Zeile eine Datei. Ich habe ein "Linienmodell" gebaut, das meinen Wünschen entspricht.

Jetzt möchte ich ein inverses Match machen ... dh ich möchte Linien mit einer Folge von 6 Buchstaben abgleichen, aber nur wenn diese sechs Buchstaben nicht Andrea sind , wie soll ich das machen?


EDIT: Ich werde das Programm schreiben, das diesen regulären Ausdruck verwendet. Ich weiß noch nicht, ob ich in Python oder PHP dieses Ding zuerst mache, um einen regulären Ausdruck zu lernen :) Es gibt verschiedene Arten von Zeilen, ich wollte regulären Ausdruck verwenden Um den Typ auszuwählen, an dem ich interessiert bin. Sobald ich diese Zeilen erhalten habe, muss ich einen anderen Filter anwenden, um nicht mit einem bekannten Wert übereinzustimmen. Ich brauche alle anderen, nicht das. Das (?! Nicht gewollt) funktioniert ganz gut, danke. :-)

Ich hoffe das klärt die Frage :)

Andrea Ambu
quelle
Es hört sich tatsächlich so an, als ob Sie es besser machen könnten, uns ein bisschen mehr Informationen über Ihre Aktivitäten zu geben und zu prüfen, ob jemand eine alternative Lösung anbieten kann. Normalerweise ist der Versuch, eine gesamte Datei zu analysieren, indem ein regulärer Ausdruck erstellt wird, der jeder Zeile entspricht, eine ziemlich komplizierte Route :)
Dan

Antworten:

70
(?!Andrea).{6}

Angenommen, Ihre Regexp-Engine unterstützt negative Lookaheads.

Bearbeiten: ..oder vielleicht möchten Sie lieber [A-Za-z]{6}anstelle von verwenden.{6}

Bearbeiten (erneut): Beachten Sie, dass Lookaheads und Lookbehinds im Allgemeinen nicht der richtige Weg sind, um eine Übereinstimmung mit regulären Ausdrücken "umzukehren". Regexps sind nicht wirklich für negative Übereinstimmungen eingerichtet, sondern überlassen dies der Sprache, mit der Sie sie verwenden.

Dan
quelle
Sie müssen das ^ hinzufügen, das @Vinko Vrsalovic verwendet, damit es nicht mit "ndrea \ n"
übereinstimmt
2
. stimmt standardmäßig nicht mit \ n überein (in einigen Sprachen [z. B. Perl] können Sie dieses Verhalten aktivieren, aber standardmäßig stimmt alles überein, ABER \ n).
Dan
1
(Außerdem erwähnte das OP nie, dass die Zeichenfolge am Anfang der Zeile auftreten musste)
Dan
1
Was meinst du mit OP?
Andrea Ambu
1
Andrea: OP bedeutet "Originalplakat", also habe ich mich auf dich bezogen :)
Dan
47

Für Python / Java

^(.(?!(some text)))*$

http://www.lisnichenko.com/articles/javapython-inverse-regex.html

Dmytro
quelle
4
Das funktioniert nicht. Sie denken an die Redewendung Tempered Greedy Token. aber der Punkt muss nach dem Lookahead gehen, nicht vorher. Siehe diese Frage . Aber dieser Ansatz ist für diese Aufgabe sowieso übertrieben.
Alan Moore
Ich weiß nicht, in welcher Sprache es geschrieben ist, aber es hat wie ein Zauber im erhabenen Text funktioniert, um meine Testdaten zu bereinigen. Vielen Dank!
Matthias Dirickx
1
@AlanMoore Eigentlich wird es für diesen Anwendungsfall fast funktionieren. Wenn some textdie Zeile jedoch gestartet wird, wird das falsche Ergebnis zurückgegeben.
Zenexer
2
@Zenexer, das habe ich gemeint. Wenn der Punkt nach dem Lookahead statt vor dem Lookahead steht, funktioniert er perfekt.
Alan Moore
Hier ist ein Link , der mehr erklärt. Ich verstehe nicht warum ?!und nicht nur !.
Timo
21

Aktualisiert mit dem Feedback von Alan Moore

In PCRE und ähnlichen Varianten können Sie tatsächlich einen regulären Ausdruck erstellen, der mit jeder Zeile übereinstimmt, die keinen Wert enthält:

^(?:(?!Andrea).)*$

Dies wird als temperiertes gieriges Zeichen bezeichnet . Der Nachteil ist, dass es nicht gut funktioniert.

Zenexer
quelle
1
Dies ist das Tempered Greedy Token in langer Form. Setzen Sie einfach den Punkt (oder [\s\S], was nur in JavaScript nützlich ist) nach den zweiten Lookahead, und Sie brauchen den ersten nicht : ^(?:(?!Andrea).)*$.
Alan Moore
@ AlanMoore Schön! Ich konnte kein etabliertes Muster finden, das so funktionierte, also habe ich mir mein eigenes ausgedacht. Anstatt dass ich Ihre Antwort nehme, sollten Sie diese als Ihre eigene angeben.
Zenexer
Das ist okay, es gibt schon viele gute Antworten. Und Sie verdienen Anerkennung dafür, dass Sie die Redewendung selbst erfunden haben. Prost!
Alan Moore
Warum schlagen Sie vor, zu verwenden [\S\s]? OP spricht von übereinstimmenden Zeilen, die kein "Andrea" -Wort enthalten. Es geht nicht darum zu überprüfen, ob die gesamte Zeichenfolge dieses Wort enthält. Vermisse ich etwas
X-Yuri
@ x-yuri Ich denke du hast recht. Ich habe wahrscheinlich die Frage beantwortet, die ich hatte, als ich diese Seite zum ersten Mal besuchte, und die Diskrepanz ignoriert. Meine Verbindung ist jedoch nicht gut genug, um die Antwort jetzt zu aktualisieren (<10 kbps)
Zenexer
11

Welche Sprache benutzt du? Hierfür sind die Funktionen und die Syntax der Regex-Implementierung von Bedeutung.

Sie könnten Look-Ahead verwenden. Am Beispiel von Python

import re

not_andrea = re.compile('(?!Andrea)\w{6}', re.IGNORECASE)

Um das aufzuschlüsseln:

(?! Andrea) bedeutet "Übereinstimmung, wenn die nächsten 6 Zeichen nicht" Andrea "sind"; wenn ja dann

\ w bedeutet ein "Wortzeichen" - alphanumerische Zeichen. Dies entspricht der Klasse [a-zA-Z0-9_]

\ w {6} bedeutet genau 6 Wortzeichen.

re.IGNORECASE bedeutet, dass Sie "Andrea", "andrea", "ANDREA" ausschließen ...

Eine andere Möglichkeit besteht darin, Ihre Programmlogik zu verwenden - verwenden Sie alle Zeilen, die nicht mit Andrea übereinstimmen, und durchlaufen Sie eine zweite Regex, um nach 6 Zeichen zu suchen. Oder prüfen Sie zuerst, ob mindestens 6 Wortzeichen vorhanden sind, und stellen Sie dann sicher, dass es nicht mit Andrea übereinstimmt.

Hamish Downer
quelle
7

Negative Lookahead-Behauptung

(?!Andrea)

Dies ist nicht gerade eine umgekehrte Übereinstimmung, aber es ist das Beste, was Sie direkt mit Regex tun können. Nicht alle Plattformen unterstützen sie jedoch.

Vinko Vrsalovic
quelle
1
Bis der Fragesteller klarstellt, sehe ich nicht, dass das Match am Anfang der Zeile beginnen muss. Warum also das ^?
Hamish Downer
Weil ich verstanden habe, dass er am Anfang der Zeile überprüfen wollte, bearbeitete gegebene Klarstellungen
Vinko Vrsalovic
5

Wenn Sie dies in RegexBuddy tun möchten, gibt es zwei Möglichkeiten, eine Liste aller Zeilen abzurufen, die nicht mit einem Regex übereinstimmen.

Stellen Sie in der Symbolleiste des Testfensters den Testbereich auf "Zeile für Zeile" ein. Wenn Sie dies tun, wird unter der Schaltfläche Alle auflisten in derselben Symbolleiste ein Element Alle Zeilen ohne Übereinstimmungen auflisten angezeigt. (Wenn die Schaltfläche Alle auflisten nicht angezeigt wird, klicken Sie in der Hauptsymbolleiste auf die Schaltfläche Übereinstimmen.)

Im GREP-Bereich können Sie die Kontrollkästchen "zeilenbasiert" und "Ergebnisse invertieren" aktivieren, um eine Liste nicht übereinstimmender Zeilen in den Dateien abzurufen, die Sie durchsuchen.

Jan Goyvaerts
quelle
5

(?!ist in der Praxis nützlich. Obwohl genau genommen, ist ein Blick nach vorne kein regulärer Ausdruck, wie er mathematisch definiert ist.

Sie können einen invertierten regulären Ausdruck manuell schreiben.

Hier ist ein Programm , um das Ergebnis automatisch zu berechnen. Das Ergebnis ist maschinell generiert, was normalerweise viel komplexer ist als das Schreiben von Hand. Aber das Ergebnis funktioniert.

schwach
quelle
1

Ich habe gerade diese Methode entwickelt, die zwar hardwareintensiv ist, aber funktioniert:

Sie können alle Zeichen, die mit dem regulären Ausdruck übereinstimmen, durch eine leere Zeichenfolge ersetzen.

Dies ist ein Oneliner:

notMatched = re.sub(regex, "", string)

Ich habe dies verwendet, weil ich gezwungen war, einen sehr komplexen regulären Ausdruck zu verwenden, und nicht herausfinden konnte, wie jeder Teil davon innerhalb einer angemessenen Zeitspanne invertiert werden kann.

Dies gibt nur das String-Ergebnis zurück, keine Match-Objekte!

Matthias Herrmann
quelle
-3

In Perl können Sie tun

process ($ line) if ($ line = ~! / Andrea /);

Phreakre
quelle
4
Diese Syntax ist falsch. Ich denke du meinst Prozess ($ line) wenn $ line! ~ / Andrea /
dland