Regulärer Ausdruck verursacht Stapelüberlauf

8

Weiter zu meiner vorherigen Frage: ECMAScript Regex für eine mehrzeilige Zeichenfolge , Ich habe das folgende Ladeverfahren implementiert:

%Vor%

Das Laden mit dieser Datei führt jedoch zu einem Stapelüberlauf (Parameter: 0x00000001, 0x00332FE4):

%Vor%

Ich konnte die Quelle des Stack-Überlaufs nicht finden, aber es sieht so aus, als wäre die äußere std::sregex_iterator -Schleife verantwortlich.

Vielen Dank im Voraus!

    
Thomas Russell 07.07.2013, 21:28
quelle

4 Antworten

4

Hier ist ein weiterer Versuch:

%Vor%

In Ihrem C ++ wäre es natürlich geschrieben als:

%Vor%

Es ist für ein minimales Backtracking gemacht (zumindest wenn es zusammenpasst), obwohl ich im Moment ein bisschen Mr. Tired-Face bin, also wahrscheinlich einige Wege verpasst habe, es zu verbessern.

Es macht zwei Annahmen , die verwendet werden, um eine Menge Backtracking zu vermeiden (was möglicherweise den Stapelüberlauf verursacht, wie andere gesagt haben):

  1. Dass es am Anfang einer Zeile nie ein === gibt, außer für die Start- / End-Markierungslinien.
  2. Dass C ++ diese Regex-Funktionen unterstützt - insbesondere die Verwendung eines negativen Lookaheads ( ?! ). Es sollte, in Anbetracht seiner ECMAScript Dialekt.

Erklärt:

%Vor%

Passen Sie die Objektstartmarkierung an und erfassen Sie sie. Das [^=] ist eine Möglichkeit, eine relativ kleine Menge an Backtracking zu vermeiden, genau wie bei Ihnen - wir verwenden nicht [^ ] , weil ich nicht weiß, ob es Leerzeichen in der OBJECT-ID gibt.

%Vor%

Beginnen Sie, eine Gruppe für Daten zu erfassen. Darin befindet sich eine nicht-einfangende Gruppe, da wir jede Zeile einzeln anpassen.

%Vor%

Negative Lookahead - wir wollen nicht === am Anfang unserer erfassten Zeile.

%Vor%

Entspricht einer Zeile einzeln.

%Vor%

Passen Sie mindestens eine Zeile zwischen Anfangs- und Endmarkierungen an, und erfassen Sie dann ALLE Zeilen in einer einzelnen Gruppe.

%Vor%

Passen Sie die Endmarke an.

Vergleich (mit RegexBuddy):

Originalversion:

  • Erste Übereinstimmung: 1277 Schritte
  • Fehlgeschlagene Übereinstimmung: 1 Schritt (dies liegt an dem Zeilenumbruch zwischen den Objekten)
  • Zweites Spiel: 396 Schritte

Jedes hinzugefügte Objekt bewirkt, dass die Anzahl der Schritte für die vorherigen vergrößert wird. Wenn beispielsweise ein weiteres Objekt (Kopie von Objekt 2, umbenannt in 3) hinzugefügt wird, ergeben sich: 2203 Schritte, 1322 Schritte, 425 Schritte.

Diese Version:

  • Erste Übereinstimmung: 67 Schritte
  • Fehlgeschlagene Übereinstimmung: 1 Schritt (erneut aufgrund des Zeilenumbruchs zwischen den Objekten)
  • Zweites Spiel: 72 Schritte
  • Fehlgeschlagene Übereinstimmung: 1 Schritt
  • Drittes Spiel: 67 Schritte
JimmiTh 17.07.2013, 17:49
quelle
4

Heiliges katastrophales Zurückverfolgen. Der Schuldige ist (?:.|\n)* . Wann immer Sie ein Konstrukt wie dieses sehen, wissen Sie, dass Sie nach Ärger fragen.

Warum? Weil Sie der Engine sagen, dass sie so oft wie möglich oder gar keinem anderen Zeichen (außer Newline) oder Newline entsprechen soll. Lass mich dich durchgehen.

Die Engine wird wie erwartet gestartet und entspricht dem === OBJECT2 === -Teil ohne größere Probleme, ein Newline wird verbraucht und die Hölle beginnt dann. Die Engine verbraucht ALLES bis hinunter zu === END OBJECT1 === und geht von dort zu einem passenden Match zurück. Backtracking bedeutet grundsätzlich, einen Schritt zurückzugehen und die Regex erneut anzuwenden, um zu sehen, ob es funktioniert. Grundsätzlich versuchen Sie alle möglichen Permutationen mit Ihrer Zeichenfolge. Dies wird in Ihrem Fall zu einigen hunderttausend Versuchen führen. Das ist wahrscheinlich der Grund, warum Sachen für dich problematisch sind.

Ich weiß nicht, ob Ihr Code besser ist oder ob er irgendwelche Fehler enthält, aber (?:.|\n)* entspricht dem Schreiben von .* mit dem * s * einzelnen Zeilenmodifikator (dot stimmt mit Zeilenumbrüchen überein) oder [\S\s]* . Wenn Sie dieses Konstrukt durch eines der beiden ersetzen, die ich empfohlen habe, werden Sie hoffentlich keinen Stapelüberlauffehler mehr sehen.

Bearbeiten: Schauen Sie sich auch die anderen Lösungen an, ich hatte nicht wirklich Zeit, in die Tiefe zu gehen und Ihnen eine solide Lösung für Ihr Problem zu bieten, zusätzlich zu erklären, warum es so schlimm ist.

    
Firas Dib 17.07.2013 12:00
quelle
1

Ihre Ausdrücke scheinen eine Menge Backtracking zu verursachen. Ich würde deine Ausdrücke ändern zu:

Erstens: ^===\s+(.*?)\s+===[\r\n]+^(.*?)[\r\n]+^===\s+END\s+\s+===

Zweitens: ^<([^>]+)>:([^<]*)

Beide Ausdrücke funktionieren mit den Optionen: Multiline und DotMatchesAll. Mit dem Start des Zeilenankers ^ wird das Backtracking auf maximal eine Zeile oder eine Gruppe begrenzt.

    
Ro Yo Mi 08.07.2013 02:49
quelle
0

Versuchen Sie stattdessen mit diesem Muster:

%Vor%     
Casimir et Hippolyte 07.07.2013 21:44
quelle