Regex für Zeichenfolge, die nicht mit dem angegebenen Suffix endet

187

Ich konnte keinen richtigen regulären Ausdruck finden, der mit einem String übereinstimmt, der nicht mit einer Bedingung endet. Zum Beispiel möchte ich nichts abgleichen, das mit einem endet a.

Das passt

b
ab
1

Das passt nicht zusammen

a
ba

Ich weiß, dass der $reguläre Ausdruck mit enden sollte , um das Ende zu markieren, obwohl ich nicht weiß, was davor stehen soll.

Bearbeiten : Die ursprüngliche Frage scheint kein legitimes Beispiel für meinen Fall zu sein. Also: Wie gehe ich mit mehr als einem Charakter um? Sagen Sie etwas, das nicht endet ab?

Ich konnte dies mithilfe dieses Threads beheben :

.*(?:(?!ab).).$

Der Nachteil dabei ist, dass es nicht mit einer Zeichenfolge aus einem Zeichen übereinstimmt.

Menno
quelle
5
Dies ist kein Duplikat der verknüpften Frage. Für den Abgleich nur gegen das Ende ist eine andere Syntax erforderlich als für den Abgleich an einer beliebigen Stelle innerhalb einer Zeichenfolge. Schauen Sie sich hier einfach die Top-Antwort an.
Jaustin
Ich stimme zu, dies ist kein Duplikat der verknüpften Frage. Ich frage mich, wie wir die obigen "Markierungen" entfernen können.
Alan Cabrera
Es gibt keinen solchen Link, den ich sehen kann.
Alan Cabrera

Antworten:

248

Sie geben uns nicht die Sprache, aber wenn Ihre Unterstützung für Regex-Aromen hinter der Behauptung steckt , brauchen Sie Folgendes:

.*(?<!a)$

(?<!a)ist eine negierte Lookbehind-Behauptung, die sicherstellt, dass vor dem Ende der Zeichenfolge (oder Zeile mit mModifikator) nicht das Zeichen "a" steht.

Sehen Sie es hier auf Regexr

Sie können dies auch problemlos mit anderen Zeichen erweitern, da diese nach der Zeichenfolge suchen und keine Zeichenklasse sind.

.*(?<!ab)$

Dies würde mit allem übereinstimmen, was nicht mit "ab" endet , siehe Regexr

Stema
quelle
1
Ich kenne RegexPAL nicht, aber Regexes unterscheiden sich in allen Sprachen und Lookbehind-Behauptungen sind eine erweiterte Funktion, die nicht von allen unterstützt wird.
Stema
7
Regexpal ist ein Javascript-basierter Regex-Tester und Javascript unterstützt keine Lookbehind-Behauptungen, was traurig ist
HamZa
Lookbehinds werden auf Regexr (Javascript) nicht unterstützt
Stealth Rabbi
1
Das Fehlen von Lookbehinds in JS bringt mich zum Weinen. Wenn Sie serverseitig arbeiten, können Sie wahrscheinlich das PCRE-Modul auf NPM oder ähnlichem verwenden, um sie direkt zu verwenden (es handelt sich um eine Reihe von Bindungen, daher glaube ich nicht, dass Sie es im Front-End verwenden können)
Eirik Birkeland
Weitere Arten von Lookahead / Lookbehind-Behauptungen: stackoverflow.com/q/2973436/12484
Jon Schneider
76

Verwenden Sie das Symbol not ( ^):

.*[^a]$

Wenn Sie das ^Symbol am Anfang von Klammern setzen, bedeutet dies "alles außer den Dingen in Klammern". $ist einfach ein Anker bis zum Ende.

Fügen Sie für mehrere Zeichen einfach alle in ihren eigenen Zeichensatz ein:

.*[^a][^b]$
tckmn
quelle
1
+1, mit der Einschränkung, dass dies nicht mit der leeren Zeichenfolge übereinstimmt (die möglicherweise wie beabsichtigt ist oder nicht), sodass die Bedeutung eher "jedes Zeichen, das nicht in Klammern steht" lautet.
Fred Foo
3
@ 0A0D: Eine Zeichenfolge mit Leerzeichen ist keine leere Zeichenfolge.
Fred Foo
7
@ 0A0D Eigentlich steht das nicht zur Debatte, das ist eine Tatsache
tckmn
8
@ Doorknob: das passt nicht aeoder cb.
Fred Foo
1
Nein, das würde auch "acb" nicht zulassen.
Menno
48

Um nach Dateien zu suchen, die nicht mit ".tmp" enden, verwenden wir den folgenden regulären Ausdruck:

^(?!.*[.]tmp$).*$

Getestet mit dem Regex Tester ergibt folgendes Ergebnis:

Geben Sie hier die Bildbeschreibung ein

Fünf o
quelle
1
Das ist interessant, eine Idee, warum das funktioniert und warum ^.*(?![.]tmp$)nicht?
Łukasz Zaroda
4
Ihr Early .*stimmt bereits mit der gesamten Zeichenfolge überein, sodass der verbleibende Ausschluss nicht mehr funktioniert.
FiveO
Für meine Zwecke hat dies funktioniert und die anderen Antworten nicht. Vielen Dank!
David Moritz
8
.*[^a]$

Der obige reguläre Ausdruck stimmt mit Zeichenfolgen überein, die nicht mit enden a.

Kent
quelle
Ich habe meine Frage erweitert, da das ursprüngliche Beispiel meinem Fall nicht vollständig zu entsprechen schien. Kannst du es lösen?
Menno
5

Versuche dies

/.*[^a]$/

Das []bezeichnet eine Zeichenklasse und das ^invertiert die Zeichenklasse so, dass sie mit allem außer einem übereinstimmt a.

JesperE
quelle
1

Die Frage ist alt, aber ich konnte keine bessere Lösung finden, die ich hier poste. Suchen Sie alle USB-Laufwerke, ohne die Partitionen aufzulisten , und entfernen Sie so den "Teil [0-9]" aus den Ergebnissen. Am Ende habe ich zwei Grep gemacht, der letzte negiert das Ergebnis:

ls -1 /dev/disk/by-path/* | grep -P "\-usb\-" | grep -vE "part[0-9]*$"

Dies führt zu meinem System:

pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0

Wenn ich nur die Partitionen haben möchte, könnte ich Folgendes tun:

ls -1 /dev/disk/by-path/* | grep -P "\-usb\-" | grep -E "part[0-9]*$"

Woher ich komme:

pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0-part1
pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0-part2

Und wenn ich es tue:

readlink -f /dev/disk/by-path/pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0

Ich bekomme:

/dev/sdb
Tombert
quelle
1

Die akzeptierte Antwort ist in Ordnung, wenn Sie Lookarounds verwenden können. Es gibt jedoch auch einen anderen Ansatz, um dieses Problem zu lösen.

Wenn wir uns den weit verbreiteten regulären Ausdruck für diese Frage ansehen:

.*[^a]$

Wir werden feststellen, dass es fast funktioniert. Es wird keine leere Zeichenfolge akzeptiert, was möglicherweise etwas unpraktisch ist. Dies ist jedoch ein kleines Problem, wenn es sich nur um ein Zeichen handelt. Wenn wir jedoch eine ganze Zeichenfolge ausschließen möchten, z. B. "abc", dann:

.*[^a][^b][^c]$

geht nicht. Zum Beispiel wird AC nicht akzeptiert.

Es gibt jedoch eine einfache Lösung für dieses Problem. Wir können einfach sagen:

.{,2}$|.*[^a][^b][^c]$

oder allgemeinere Version:

.{,n-1}$|.*[^firstchar][^secondchar]$ wobei n Länge der Zeichenfolge , die Sie verbieten möchten ( abces 3 ist) und firstchar, secondchar, ... sind erste, zweite ... n - te Zeichen der Zeichenfolge (für abcsie wäre a, dann b, dann c).

Dies ergibt sich aus einer einfachen Beobachtung, dass eine Zeichenfolge, die kürzer als der Text ist, den wir nicht verbieten, diesen Text per Definition nicht enthalten kann. Wir können also entweder alles akzeptieren, was kürzer ist ("ab" ist nicht "abc"), oder alles, was lang genug ist, um es zu akzeptieren, aber ohne das Ende.

Hier ist ein Beispiel für eine Suche, mit der alle Dateien gelöscht werden, die nicht .jpg sind:

find . -regex '.{,3}$|.*[^.][^j][^p][^g]$' -delete

MatthewRock
quelle
.{,2}$|.*[^a][^b][^c]$stimmt nicht übereinccc
psalaets
0

Alles, was mit etwas übereinstimmt, das mit einem --- endet. .*a$Wenn Sie also mit dem regulären Ausdruck übereinstimmen, negieren Sie die Bedingung, oder Sie können alternativ auch tun, .*[^a]$wo [^a]alles bedeutet, was istnot a

Rechnung
quelle
0

Wenn Sie verwenden grepoder seddie Syntax wird ein wenig anders sein. Beachten Sie, dass die sequentielle [^a][^b]Methode hier nicht funktioniert:

balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n'
jd8a
8$fb
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a]$"
8$fb
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^b]$"
jd8a
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^c]$"
jd8a
8$fb
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a][^b]$"
jd8a
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a][^c]$"
jd8a
8$fb
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a^b]$"
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a^c]$"
8$fb
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^b^c]$"
jd8a
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^b^c^a]$"

FWIW, ich finde die gleichen Ergebnisse in Regex101 , was meiner Meinung nach JavaScript-Syntax ist.

Schlecht: https://regex101.com/r/MJGAmX/2
Gut: https://regex101.com/r/LzrIBu/2

abalter
quelle