Was ist der Unterschied zwischen .*? und. * reguläre Ausdrücke?


141

Ich versuche, einen String mit Regex in zwei Teile aufzuteilen. Die Zeichenfolge ist wie folgt formatiert:

text to extract<number>

Ich habe verwendet (.*?)<und <(.*?)>welche funktionieren gut, aber nachdem ich ein wenig in Regex gelesen habe, habe ich mich gerade gefragt, warum ich das ?in den Ausdrücken brauche . Ich habe es erst so gemacht, nachdem ich sie über diese Seite gefunden habe, also bin ich mir nicht ganz sicher, was der Unterschied ist.


Antworten:


171

Es ist der Unterschied zwischen gierigen und nicht gierigen Quantifizierern.

Betrachten Sie die Eingabe 101000000000100.

Verwenden 1.*1, *ist gierig - es wird bis zum Ende übereinstimmen und dann zurückverfolgen, bis es übereinstimmen kann 1, so dass Sie mit 1010000000001.
.*?ist nicht gierig. *wird mit nichts übereinstimmen, wird dann aber versuchen, zusätzliche Zeichen zuzuordnen, bis sie übereinstimmen 1, und schließlich übereinstimmen 101.

Alle quantifiers haben einen nicht-gierigen Modus: .*?, .+?, .{2,6}?, und sogar .??.

In Ihrem Fall könnte ein ähnliches Muster sein <([^>]*)>- es entspricht nichts anderem als einem Größer-als-Zeichen (genau genommen entspricht es null oder mehr Zeichen außer >dazwischen <und >).

Siehe Quantifier Cheat Sheet .


Ah toll, ich mag das letzte von allem außer dem> Zeichen!
Doug

1
Können Sie ein Beispiel erklären oder zeigen, wie sich das Gierige ?vom Nicht-Gierigen unterscheidet ???
AdrianHHH

4
Sicher. Für die Zeichenfolge würde "abc"der reguläre Ausdruck /\w\w?\w/mit der vollständigen Zeichenfolge übereinstimmen "abc"- da dies ?gierig ist. /\w\w??\w/ist faul - es wird nur passen "ab". Es wird nur zurückverfolgt und abgeglichen, "abc"wenn es später fehlschlägt.
Kobi

184

Auf gierig gegen nicht gierig

Die Wiederholung in Regex ist standardmäßig gierig : Sie versuchen, so viele Wiederholungen wie möglich abzugleichen. Wenn dies nicht funktioniert und sie zurückverfolgen müssen, versuchen sie, jeweils eine Wiederholung weniger abzugleichen, bis eine Übereinstimmung des gesamten Musters vorliegt gefunden. Wenn ein Match schließlich stattfindet, würde eine gierige Wiederholung so vielen Wiederholungen wie möglich entsprechen.

Der ?als Wiederholungsquantifizierer ändert dieses Verhalten in nicht gierig , auch widerstrebend genannt ( in z. B. Java ) (und manchmal "faul"). Im Gegensatz dazu wird bei dieser Wiederholung zunächst versucht, so wenig Wiederholungen wie möglich zuzuordnen. Wenn dies nicht funktioniert und sie zurückverfolgen müssen, beginnen sie, jeweils eine weitere Wiederholung abzugleichen. Wenn ein Match schließlich stattfindet, würde eine widerstrebende Wiederholung so wenig Wiederholungen wie möglich entsprechen.

Verweise


Beispiel 1: Von A bis Z.

Vergleichen wir diese beiden Muster: A.*Zund A.*?Z.

Angesichts der folgenden Eingabe:

eeeAiiZuuuuAoooZeeee

Die Muster ergeben die folgenden Übereinstimmungen:

Konzentrieren wir uns zunächst auf das, was A.*Ztut. Wenn es mit dem ersten übereinstimmt , versucht Ader .*, der gierig ist, zuerst so viele .wie möglich zu finden.

eeeAiiZuuuuAoooZeeee
   \_______________/
    A.* matched, Z can't match

Da das Znicht übereinstimmt, fährt der Motor zurück und .*muss dann eins weniger übereinstimmen .:

eeeAiiZuuuuAoooZeeee
   \______________/
    A.* matched, Z still can't match

Dies passiert noch einige Male, bis wir schließlich dazu kommen:

eeeAiiZuuuuAoooZeeee
   \__________/
    A.* matched, Z can now match

Jetzt Zkann übereinstimmen, so dass das Gesamtmuster übereinstimmt:

eeeAiiZuuuuAoooZeeee
   \___________/
    A.*Z matched

Im Gegensatz dazu entspricht die widerstrebende Wiederholung in den A.*?Zersten Spielen so wenig .wie möglich und nimmt dann mehr .als nötig. Dies erklärt, warum in der Eingabe zwei Übereinstimmungen gefunden werden.

Hier ist eine visuelle Darstellung der Übereinstimmung der beiden Muster:

eeeAiiZuuuuAoooZeeee
   \__/r   \___/r      r = reluctant
    \____g____/        g = greedy

Beispiel: Eine Alternative

In vielen Anwendungen sind die beiden Übereinstimmungen in der obigen Eingabe erwünscht, daher .*?wird anstelle der Gier eine Zurückhaltung verwendet .*, um eine Überanpassung zu verhindern. Für dieses spezielle Muster gibt es jedoch eine bessere Alternative, wenn eine negierte Zeichenklasse verwendet wird.

Das Muster A[^Z]*Zfindet auch die gleichen zwei Übereinstimmungen wie das A.*?ZMuster für die obige Eingabe ( wie auf ideone.com zu sehen ). [^Z]wird als negierte Zeichenklasse bezeichnet : Sie passt zu allem anderen Z.

Der Hauptunterschied zwischen den beiden Mustern besteht in der Leistung: Da die negierte Zeichenklasse strenger ist, kann sie für eine bestimmte Eingabe nur in eine Richtung übereinstimmen. Es spielt keine Rolle, ob Sie für dieses Muster einen gierigen oder widerstrebenden Modifikator verwenden. In einigen Geschmacksrichtungen können Sie sogar noch bessere Ergebnisse erzielen und einen sogenannten Possessiv-Quantifizierer verwenden, der überhaupt nicht zurückverfolgt.

Verweise


Beispiel 2: Von A nach ZZ

Dieses Beispiel sollte veranschaulichend sein: Es zeigt, wie die gierigen, widerstrebenden und negierten Zeichenklassenmuster bei gleicher Eingabe unterschiedlich übereinstimmen.

eeAiiZooAuuZZeeeZZfff

Dies sind die Übereinstimmungen für die obige Eingabe:

Hier ist eine visuelle Darstellung dessen, was sie übereinstimmten:

         ___n
        /   \              n = negated character class
eeAiiZooAuuZZeeeZZfff      r = reluctant
  \_________/r   /         g = greedy
   \____________/g

verwandte Themen

Hierbei handelt es sich um Links zu Fragen und Antworten zum Stapelüberlauf, die einige Themen abdecken, die möglicherweise von Interesse sind.

Eine gierige Wiederholung kann eine andere übertreffen


1
Ich wollte rubular.com sagen, nicht ideone.com. Für andere: Überarbeiten Sie diesen Beitrag nicht für mich, ich mache ihn bei der nächsten Überarbeitung zusammen mit anderen Beispielen selbst. Fühlen Sie sich frei, Feedback, Vorschläge usw. in Kommentaren zu geben, damit ich diese auch einbeziehen kann.
Polygenelubricants


4
Diese Antwort wurde zu den häufig gestellten Fragen zum Stapelüberlauf für reguläre Ausdrücke unter "Quantifizierer> Mehr zu den Unterschieden ..."
hinzugefügt

Diese Antwort verdient es wirklich, die gewählte Antwort zu sein!. Vielen Dank für Ihre ausführliche Erklärung.
masky007

Ich habe das Tag nicht gierig hinzugefügt . Warum, weil die Frage es brauchte, aber auch, weil es mehr Benutzer zu dieser großartigen Antwort führen wird. Mit anderen Worten, wenn Sie eine gute Antwort geben und die Antwort ein Tag verwendet, das nicht in der Frage enthalten ist, fügen Sie das Tag hinzu, da das OP nicht wusste, dass das Tag offenbar ist.
Guy Coder

20

Angenommen, Sie haben:

<a></a>

<(.*)>würde passen, a></awo wie <(.*?)>passen würde a. Letzterer stoppt nach dem ersten Spiel von >. Es wird nach einer oder 0 Übereinstimmungen .*gefolgt vom nächsten Ausdruck gesucht.

Der erste Ausdruck <(.*)>hört nicht auf, wenn er mit dem ersten übereinstimmt >. Es wird bis zum letzten Spiel von fortgesetzt >.


Dies ist leichter zu verstehen als die obige Erklärung.
Prometheus
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.