Wie kann man einen Teil einer Regex abgleichen, aber nicht erfassen?


209

Ich habe eine Liste von Zeichenfolgen. Einige von ihnen haben die Form 123-...456. Der variable Teil "..." kann sein:

  • die Zeichenfolge "Apfel" gefolgt von einem Bindestrich, z 123-apple-456
  • die Zeichenfolge "Banane" gefolgt von einem Bindestrich, z 123-banana-456
  • eine leere Zeichenfolge, z. B. 123-456(beachten Sie, dass es nur einen Bindestrich gibt)

Jedes andere Wort als "Apfel" oder "Banane" ist ungültig.

Für diese drei Fälle möchte ich "Apfel", "Banane" bzw. "" zuordnen. Beachten Sie, dass ich will nie erfassen den Bindestrich, aber ich will immer passen es. Wenn die Zeichenfolge nicht die 123-...456oben beschriebene Form hat, gibt es überhaupt keine Übereinstimmung.

Wie schreibe ich dazu einen regulären Ausdruck? Angenommen, ich habe einen Geschmack, der Lookahead-, Lookbehind-, Lookaround- und nicht erfassende Gruppen zulässt.


Die wichtigste Beobachtung hier ist, dass Sie, wenn Sie entweder "Apfel" oder "Banane" haben, auch den nachgestellten Bindestrich haben müssen, aber nicht damit übereinstimmen möchten. Und wenn Sie mit der leeren Zeichenfolge übereinstimmen, darf der nachfolgende Bindestrich nicht vorhanden sein. Ein regulärer Ausdruck, der diese Behauptung zusammenfasst, wird meiner Meinung nach der richtige sein.


Sie möchten alles außer Bindestrichen abgleichen?
BrunoLM

Antworten:


285

Die einzige Möglichkeit, etwas nicht zu erfassen, besteht darin, sich umzuschauen :

(?<=123-)((apple|banana)(?=-456)|(?=456))

Denn selbst bei nicht erfassenden Gruppen(?:…) erfasst der gesamte reguläre Ausdruck den übereinstimmenden Inhalt. Dieser reguläre Ausdruck stimmt jedoch nur überein appleoder bananawenn ihm vorangestellt 123-und gefolgt wird -456, oder er stimmt mit der leeren Zeichenfolge überein, wenn ihm vorangestellt 123-und gefolgt wird 456.

|Lookaround  |    Name      |        What it Does                       |
-----------------------------------------------------------------------
|(?=foo)     |   Lookahead  | Asserts that what immediately FOLLOWS the |
|            |              |  current position in the string is foo    |
-------------------------------------------------------------------------
|(?<=foo)    |   Lookbehind | Asserts that what immediately PRECEDES the|
|            |              |  current position in the string is foo    |
-------------------------------------------------------------------------
|(?!foo)     |   Negative   | Asserts that what immediately FOLLOWS the |
|            |   Lookahead  |  current position in the string is NOT foo|
-------------------------------------------------------------------------
|(?<!foo)    |   Negative   | Asserts that what immediately PRECEDES the|
|            |   Lookbehind |  current position in the string is NOT foo|
-------------------------------------------------------------------------

1
+1 - In diesem Fall können Sie dies umgehen, indem Sie Gruppe 1 anstelle von Gruppe 0 verwenden. Dies ist jedoch eine hervorragende (und subtile!) Unterscheidung.
Ben Blank

@ Ben Blank: Es hängt definitiv davon ab, wie "Match" und "Capture" interpretiert werden.
Gumbo

8
Wird in JavaScript nicht unterstützt, yay ! wäre schön, eine JS-freundliche Methode zu haben, aber überhaupt nicht schlecht, +0,5 (
aufgerundet

Ich liebe es, mich umzusehen! Diese funktionieren auch hervorragend mit Ruby.
Rots

perfekte Lösung, ich liebe das
Trần Quang Hiệp

15

Update: Danke an Germán Rodríguez Herrera!

In Javascript versuchen Sie: /123-(apple(?=-)|banana(?=-)|(?!-))-?456/

Denken Sie daran, dass das Ergebnis in Gruppe 1 ist

Debuggex-Demo


8

Versuchen:

123-(?:(apple|banana|)-|)456

Das wird passen apple, bananaoder eine leere Zeichenfolge, und nach ihm wird es ein 0 oder 1 Bindestrich sein. Ich habe mich geirrt, weil ich keine Erfassungsgruppe brauchte. Wie dumm von mir.


Dies ist nicht korrekt, da es beispielsweise mit "123-Kokosnuss-456" übereinstimmt.
David Stone

Ich dachte du wolltest es allgemeiner ... behoben.
Thomas

5

Ich habe eine der Antworten geändert (von @ op1ekun):

123-(apple(?=-)|banana(?=-)|(?!-))-?456

Der Grund ist, dass die Antwort von @ op1ekun auch übereinstimmt "123-apple456", ohne den Bindestrich nach Apfel.


3

Versuche dies:

/\d{3}-(?:(apple|banana)-)?\d{3}/

1
Dies ist nicht korrekt, da es beispielsweise mit "123-Kokosnuss-456" übereinstimmt.
David Stone

@david: Wie unterscheidet sich das von deinem "Bananen" -Beispiel?
SilentGhost

@ SilentGhost: Ich möchte nur erfassen appleoder bananaoder "". Alle anderen Werte sind ungültig, wie ich bereits sagte.
David Stone

sry, in diesem Fall: / \ d {3} - (? :( Apfel | Banane) -)? \ d {3} /
slosd

1
Dieses Beispiel zeigt, dass es möglich ist, eine nicht erfassende Gruppe zu haben, ohne Lookahead und Lookbehind zu verwenden.
Vince Panuccio

0

Eine Variation des Ausdrucks von @Gumbo, die \Kzum Zurücksetzen von Übereinstimmungspositionen verwendet wird, um die Einbeziehung von Zahlenblöcken in die Übereinstimmung zu verhindern. Verwendbar in PCRE-Regex-Geschmacksrichtungen.

123-\K(?:(?:apple|banana)(?=-456)|456\K)

Streichhölzer:

Match 1  apple
Match 2  banana
Match 3

-3

Bei weitem das einfachste (funktioniert für Python) ist '123-(apple|banana)-?456'.


1
Dies würde übereinstimmen, 123-apple456so dass es nicht korrekt ist.
Loren
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.