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.

David Stone
quelle
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|
-------------------------------------------------------------------------
Gumbo
quelle
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

op1ekun
quelle
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.

Thomas
quelle
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.

Germán Rodríguez Herrera
quelle
3

Versuche dies:

/\d{3}-(?:(apple|banana)-)?\d{3}/
slosd
quelle
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
oriberu
quelle
-3

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

johmsp
quelle
1
Dies würde übereinstimmen, 123-apple456so dass es nicht korrekt ist.
Loren