was ist der Unterschied zwischen ?:, ?! und? = in Regex?

105

Ich suchte nach der Bedeutung dieser Ausdrücke, konnte aber den genauen Unterschied zwischen ihnen nicht verstehen. Das sagen sie:

  • ?: Ausdruck ausgleichen, aber nicht erfassen.
  • ?= Passen Sie ein Suffix an, schließen Sie es jedoch von der Erfassung aus.
  • ?! Übereinstimmung, wenn kein Suffix vorhanden ist.

Ich habe versucht, diese in einfachem RegEx zu verwenden, und habe für alle ähnliche Ergebnisse erzielt. Beispiel: Die folgenden 3 Ausdrücke ergeben sehr ähnliche Ergebnisse.

  • [a-zA-Z0-9._-]+@[a-zA-Z0-9-]+(?!\.[a-zA-Z0-9]+)*
  • [a-zA-Z0-9._-]+@[a-zA-Z0-9-]+(?=\.[a-zA-Z0-9]+)*
  • [a-zA-Z0-9._-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9]+)*
RK Poddar
quelle
Bitte zeigen Sie uns Ihren Testfall. Sie sollten nicht die gleichen Ergebnisse liefern.
Bergi
@ sepp2k, es gibt in wenigen Fällen die gleichen ähnlichen Ergebnisse, von denen einer in der Frage erwähnt wird.
RK Poddar
@Bergi, ich habe es mit zufälligen Daten getestet, die englische Wörter, Telefonnummern, URLs, E-Mail-Adressen, Nummern usw. enthalten.
RK Poddar
4
@RKAgarwal Ah, ich sehe, was du dort gemacht hast. Sie haben *nach den Gruppen ein a hinzugefügt , damit sie einfach ignoriert werden.
sepp2k
noobie note : Sie würden diese nur am Anfang der Klammer verwenden und Klammern bilden eine Erfassungsgruppe (verschiedene Klammersätze extrahieren verschiedene Textabschnitte).
Ryan Taylor

Antworten:

149

Der Unterschied zwischen ?=und ?!besteht darin, dass der erstere erfordert, dass der angegebene Ausdruck übereinstimmt, und der letztere erfordert, dass er nicht übereinstimmt. Zum Beispiel a(?=b)wird das "a" in "ab" übereinstimmen, aber nicht das "a" in "ac". Wobei a(?!b)das "a" in "ac" übereinstimmt, aber nicht das "a" in "ab".

Der Unterschied zwischen ?:und ?=besteht darin, dass ?=der Ausdruck von der gesamten Übereinstimmung ausgeschlossen wird, während ?:keine Erfassungsgruppe erstellt wird. So stimmt beispielsweise a(?:b)das "ab" in "abc" a(?=b)überein , während nur das "a" in "abc" übereinstimmt. a(b)würde mit dem "ab" in "abc" übereinstimmen und ein Capture erstellen, das das "b" enthält.

sepp2k
quelle
78
?:  is for non capturing group
?=  is for positive look ahead
?!  is for negative look ahead
?<= is for positive look behind
?<! is for negative look behind

Bitte überprüfen Sie hier: http://www.regular-expressions.info/lookaround.html für ein sehr gutes Tutorial und Beispiele zu Lookahead in regulären Ausdrücken.

Anubhava
quelle
15
JavaScript kennt sich jedoch nicht mit Lookbehind aus.
Bergi
1
Dieser ist vollständiger für allgemeine Regex.
Yan Yang
/ (? <= ^ a) b / arbeitete für mich in Javascript! Es scheint kein Tutorial zu geben, um in Javascript im Internet nachzuschauen.
Y. Yoshii
Nur neuere Versionen von Browsern unterstützen Look
Behind
- anubhava Ich kenne keine Alternative zu / (? <= ^ A) b / mit dem reinen regulären Ausdruck. Vielleicht kann ich, aber ich müsste mich auf Rückruffunktionen verlassen.
Y. Yoshii
21

Zum besseren Verständnis wenden wir die drei Ausdrücke plus eine Erfassungsgruppe an und analysieren jedes Verhalten.

  • () Erfassungsgruppe - Der reguläre Ausdruck in der Klammer muss übereinstimmen, und die Übereinstimmung muss eine Erfassungsgruppe erstellen
  • (?:) Nicht erfassende Gruppe - Der reguläre Ausdruck in der Klammer muss übereinstimmen, erstellt jedoch keine erfassende Gruppe
  • (?=) positiver Blick nach vorne - behauptet, dass der reguläre Ausdruck übereinstimmen muss
  • (?!) negativer Blick nach vorne - behauptet, dass es unmöglich ist, den regulären Ausdruck zu erreichen

Lassen Sie uns beantragen q(u)i, um zu beenden . qstimmt mit q überein und die Erfassungsgruppe ustimmt mit u überein . Die Übereinstimmung innerhalb der Erfassungsgruppe wird genommen und eine Erfassungsgruppe wird erstellt. Also geht der Motor weiter i. Und ipasst auf i . Dieser letzte Matchversuch ist erfolgreich. qui wird abgeglichen und eine Erfassungsgruppe mit u erstellt.

Lassen Sie uns beantragen q(?:u)i, um zu beenden . Wieder qstimmt mit q überein und die nicht erfassende Gruppe ustimmt mit u überein . Die Übereinstimmung aus der nicht erfassenden Gruppe wird übernommen, aber die erfassende Gruppe wird nicht erstellt. Also geht der Motor weiter i. Und ipasst auf i . Dieser letzte Matchversuch ist erfolgreich. qui ist abgestimmt

Lassen Sie uns beantragen q(?=u)i, um zu beenden . Der Lookahead ist positiv und wird von einem weiteren Token gefolgt. Wieder qstimmt mit q und umit u überein . Auch hier muss die Übereinstimmung vom Lookahead verworfen werden, damit der Motor von ider Zeichenfolge zu u zurücktritt . Der Lookahead war erfolgreich, daher fährt der Motor fort i. Aber inicht mithalten können u . Dieser Matchversuch schlägt also fehl.

Lassen Sie uns beantragen q(?=u)u, um zu beenden . Der Lookahead ist positiv und wird von einem weiteren Token gefolgt. Wieder qstimmt mit q und umit u überein . Die Übereinstimmung vom Lookahead muss verworfen werden, damit der Motor von uder Zeichenfolge zurück zu u tritt . Der Lookahead war erfolgreich, daher fährt der Motor fort u. Und upasst auf u . Dieser Matchversuch ist also erfolgreich. qu ist abgestimmt

Lassen Sie uns beantragen q(?!i)u, um zu beenden . Auch in diesem Fall ist Lookahead positiv (weil ies nicht übereinstimmt) und wird von einem weiteren Token gefolgt. Wieder qstimmt mit q überein und istimmt nicht mit u überein . Die Übereinstimmung vom Lookahead muss verworfen werden, damit der Motor von uder Zeichenfolge zurück zu u tritt . Der Lookahead war erfolgreich, daher fährt der Motor fort u. Und upasst auf u . Dieser Matchversuch ist also erfolgreich. qu ist abgestimmt

Zusammenfassend geht es also um den wirklichen Unterschied zwischen Lookahead- und Nicht-Capturing-Gruppen, wenn Sie nur die Existenz testen oder das Match testen und speichern möchten. Erfassungsgruppen sind teuer, verwenden Sie sie also mit Bedacht.

freedev
quelle
> Also tritt der Motor von i in der Zeichenfolge zu u zurück. Der Lookahead war erfolgreich, daher fährt der Motor mit i fort. Aber ich kann nicht mit dir mithalten. Das ist total verwirrend. Warum zurücktreten, wenn dies Lookahead ist ?
Grüner
1
@Green Eine wichtige Sache, die Sie über Lookahead und andere Lookaround-Konstrukte wissen sollten, ist, dass sie zwar die Bewegungen durchlaufen, um festzustellen, ob ihr Unterausdruck übereinstimmt, aber keinen Text „verbrauchen“. Das mag etwas verwirrend sein
freedev
7

Versuchen Sie, foobardiese zu vergleichen:

/foo(?=b)(.*)/
/foo(?!b)(.*)/

Der erste reguläre Ausdruck (?=b)stimmt überein und gibt als ersten Submatch "bar" zurück - entspricht dem 'b', verbraucht ihn jedoch nicht und belässt ihn in den folgenden Klammern.

Der zweite reguläre Ausdruck stimmt NICHT überein, da erwartet wird, dass auf "foo" etwas anderes als "b" folgt.

(?:...)hat genau den gleichen Effekt wie einfach (...), gibt diesen Teil jedoch nicht als Submatch zurück.

lanzz
quelle
0

Der einfachste Weg, Behauptungen zu verstehen, besteht darin, sie als den Befehl zu behandeln, der in einen regulären Ausdruck eingefügt wird. Wenn der Motor zu einer Zusicherung läuft, prüft er sofort den durch die Zusicherung beschriebenen Zustand. Wenn das Ergebnis wahr ist, fahren Sie mit dem regulären Ausdruck fort.

BlackGlory
quelle
0

Das ist der wahre Unterschied:

>>> re.match('a(?=b)bc', 'abc')
<Match...>
>>> re.match('a(?:b)c', 'abc')
<Match...>

# note:
>>> re.match('a(?=b)c', 'abc')
None

Wenn Sie den Inhalt nach "?:" Oder "? =" Nicht interessieren, sind "?:" Und "? =" Genau gleich. Beide sind in Ordnung zu benutzen.

Wenn Sie diese Inhalte jedoch für den weiteren Prozess benötigen (nicht nur für das Ganze. In diesem Fall können Sie einfach "a (b)" verwenden), müssen Sie stattdessen "? =" Verwenden. Ursache "?:" Wird gerade durch weg.

TeaDrinker
quelle