5

Ich habe den folgenden regulären Ausdruck in zwei verschiedenen Sprachen, der die gleichen ungeraden Ergebnisse (javaScript und Flash) erzeugt. Was ich wissen möchte, ist nicht, wie es zu beheben ist, aber warum das Verhalten auftritt?Regex erfasst nur die letzte Instanz der Erfassungsgruppe in Übereinstimmung

Die Regular Expression:

\[(\\{2}|\\\]|[^\]])*\] 

Das Ziel hier ist es, eine klammert Zeichenfolge, anzupassen und sicherzustellen, dass ich nicht an einem entflohenen Klammer Halt machen.

Wenn ich die Texteingabe [abcdefg] habe, ist es korrekt zugeordnet, aber das einzige, was als Teil der Erfassungsgruppe zurückgegeben wird, ist g, wo ich wie erwartet abcdefg erwarte. Wenn ich den Ausdruck zu \[((?:\\{2}|\\\]|[^\]])*)\] ändere, dann bekomme ich das Ergebnis, das ich will.

Warum passiert das? Wird dies in anderen Sprachen konsistent sein?

Hinweis: Simplifing der Ausdruck zu \[([^\]])*\] erzeugt das gleiche Problem.

Antwort

7

Unabhängig von dem Problem, Actionscript und JavaScript immer die gleichen Ergebnisse liefern sollten, da sie beide ECMAScript implementieren (oder eine Übergruppe davon, aber für reguläre Ausdrücke sollten sie nicht widersprechen).

Aber ja, das wird in jeder Sprache (oder besser gesagt Regex-Geschmack) passieren. Der Grund ist, dass Sie die einfangende Gruppe wiederholen. Nehmen wir ein einfacheres Beispiel: passen Sie (.)* gegen abc an. Was wir also wiederholen, ist (.). Wenn es das erste Mal versucht wird, tritt der Motor in die Gruppe ein, passt a mit ., verlässt die Gruppe und erfasst a. Erst jetzt tritt der Quantifizierer ein und wiederholt das Ganze. Also betreten wir die Gruppe erneut und passen und erfassen b. Diese Erfassung überschreibt die vorherige, daher enthält \1 jetzt b. Gleiches nochmal für die dritte Wiederholung: Die Aufnahme wird mit c überschrieben.

Ich kenne keinen Regex-Flavour, der sich anders verhält, und der einzige, mit dem Sie auf alle früheren Captures zugreifen können (anstatt sie einfach zu überschreiben), ist .NET.

Die Lösung ist die eine p.s.g. vorgeschlagen. Machen Sie die Gruppierung, die Sie für die Nichtaufnahme der Wiederholung benötigen (dies verbessert die Leistung, da Sie sowieso nicht alles erfassen und überschreiben müssen) und wickeln Sie das Ganze in eine neue Gruppe ein. Ihr Ausdruck hat jedoch einen kleinen Fehler: Sie müssen den umgekehrten Schrägstrich in die Klasse negierter Zeichen einschließen. Andernfalls könnte Backtracking Ihnen eine Übereinstimmung in [abc\] geben. Also hier ist ein Ausdruck, wie man es erwarten funktioniert:

\[((?:\\{2}|\\\]|[^\]\\])*)\] 

Working demo. (leider ist es nicht die Aufnahmen zeigen, aber es zeigt, dass es richtig Spiele in allen Fällen gibt)

Beachten Sie, dass Ihre Der Ausdruck erlaubt keine anderen Escape-Sequenzen. Insbesondere ein einzelnes \, gefolgt von allem anderen als einem ] wird dazu führen, dass Ihr Muster fehlschlägt.Wenn dies nicht das, was Sie wünschen, können Sie einfach verwenden:

\[((?:\\.|[^\]\\])*)\] 

Working demo.

Leistung kann weiter mit der "unrolling-the-loop" Technik verbessert werden:

\[([^\]\\]*(?:\\.[^\]\\]*)*)\] 

Working demo.

2

Versuchen einschließlich der * quantifier innerhalb der Capture-Gruppe, wie folgt aus:

\[((?:\\{2}|\\\]|[^\]])*)\] 
Verwandte Themen