Java Regex stirbt beim Stack-Überlauf: Benötige eine bessere Version

8

Ich arbeite an einem JMD (Java MarkDown) (ein Java-Port von MarkDownSharp ), aber ich habe gerade ein Problem mit einer Regex. Für die Datei Markdown_Documentation_Syntax.text stirbt dieser reguläre Ausdruck:

%Vor%

was übersetzt:

%Vor%

Dieses Muster sucht nach akzeptierten Block-Tags, die am Anfang einer Zeile verankert sind, gefolgt von einer beliebigen Anzahl von Zeilen, und wird dann von einem passenden Tag gefolgt von einem Newline- oder einem String-Terminator abgeschlossen. Dies erzeugt:

%Vor%

Dies kann durch Erhöhen des Stack-Speicherplatzes für Java (standardmäßig 128k / 400k für oss / ss IIRC) behoben werden, aber der obige Ausdruck ist sowieso langsam.

Ich suche also nach einem Regex-Guru, der es besser kann (oder zumindest das Leistungsproblem mit diesem Muster erklären kann). Die C # Version ist ein wenig langsam, aber funktioniert gut. PHP scheint damit auch keine Probleme zu haben.

Bearbeiten: Dies ist auf JDK6u17 unter Windows 7 64 Ultimate.

    
cletus 04.01.2010, 02:34
quelle

3 Antworten

16

Dieser Teil:

%Vor%

wird wegen der verschachtelten * VIELE unnötige Rückverfolgung beinhalten und da es Zeichen gibt, die danach übereinstimmen müssen.

Ich habe in Perl einen schnellen Benchmark für einige beliebige Strings erstellt und eine Verbesserung von 13-15% erzielt, indem ich das Stück auf

umgestellt habe %Vor%

, das nicht erfassende, unabhängige Untergruppierung durchführt. Das bringt Ihnen zwei Vorteile: Es verschwendet keine Zeit mehr, die passende Zeichenfolge zu erfassen, und noch wichtiger ist, dass es nicht mehr auf die innerste .* zurückführt, was ohnehin Zeitverschwendung ist. Es gibt keine Möglichkeit, dass nur ein Teil von. * Zu einer gültigen Übereinstimmung führt, sodass explizit alles oder nichts helfen sollte.

Ich weiß nicht, ob das in diesem Fall eine ausreichende Verbesserung ist.

    
Rob Van Dam 04.01.2010, 05:14
quelle
2

Obwohl die Verbesserung des Musters hilfreich und ratsam ist, ist Javas Pattern Matcher rekursiv und es ist im Allgemeinen das Beste, zu einer iterativen Lösung zu wechseln.

Als ich ähnliche Probleme hatte, wechselte ich zu jregex ( Ссылка ) und das funktionierte für mich.

Die Musterübereinstimmung ist jetzt vielleicht mit der verbesserten Lösung gelungen, aber sie kann fehlschlagen, wenn ein 10 mal so großer Text gegeben wurde.

PS: Sorry für das Nekromantieren eines alten Themas, aber dieser Thread hat einen hohen Rang bei Google und es würde den Leuten nützen, wenn ich es hier einfügen würde

    
Harsh 22.04.2011 14:32
quelle
0

Der Unterausdruck: "(.*\n)*?" (und die verbesserte Version der akzeptierten Antwort: "(?>.*\n)*?" ) haben beide ein Problem: Sie können ein Blockelement, das in einer Zeile geschrieben ist, nicht zuordnen. Mit anderen Worten, sie stimmen nicht überein:

%Vor%

Wenn dies nicht das gewünschte Verhalten ist, ist eine korrekte (und viel effizientere) Lösung einfach zu verwenden:

.*?

Und schalten Sie den Single-Line-Modus ein.

    
ridgerunner 22.04.2011 16:01
quelle

Tags und Links