2009-04-29 9 views
3

die die beiden folgenden Zeilen in C# (mit Rahmen .NET 3,5)Wie handhaben Spiele von Benutzern übermittelten Regexes nicht enden wollende

Regex regex = new Regex(@"^((E|e)t)?(M|m)oi (?<NewName>[A-Za-z]\.?\w*((\-|\s)?[A-Za-z]?\w{1,})+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase); 
Match m = regex.Match("moi aussi jaimerai etre un ordinateur pour pas m'énnerver "); 

(leider ist es ein französisch-Programm :))

Wenn sie Lassen betrachten ausgeführt werden, bleibt der Prozess in der Match()-Methode hängen und wird nie beendet. Ich denke, es gibt ein Problem mit dem Leerraum im Regex-Muster, aber ich möchte das Muster nicht ändern (es wird tatsächlich außerhalb des Programms von den Endbenutzern meines Tools gesetzt), aber ich kann den Prozess stoppen (mit einem Timeout zum Beispiel).

Weiß jemand, ob dies ein wohlbekanntes Problem mit dem .NET Regulären Ausdruck ist und ob es einen einfachen Weg gibt, um es zu umgehen oder muss ich diese Zeilen fädeln und sie bei Bedarf abbrechen (definitiv nicht mag das tun).

+2

Nein, es ist ein bekanntes Problem, dass Benutzer ihre eigenen regulären Ausdrücke eingeben dürfen. : -/ –

+0

Pb.NET? Ist das die französische Version von VB.NET? Entschuldigung, ich lerne immer noch diese beiden Sprachen. : P – Cerebrus

+1

@PierrOz: Ihre Frage scheint irreführend zu sein. Es geht nicht um die Regex. Es geht um den Prozess und wie man es abbricht, wenn es zu lange dauert. Aber alle Antworten, die Sie bekommen, werden Ihnen sagen, wie Sie Ihren Regex optimieren können. Meiner Meinung nach fragen Sie das nicht. – Cerebrus

Antwort

1

Ich denke, Sie sollten einfach die Regex-Übereinstimmung in einem separaten Thread starten und erlauben, dass es abgebrochen wird, wenn ein bestimmtes maximales Zeitlimit erreicht ist.

-1

Im Allgemeinen können reguläre Ausdrücke länger dauern als erwartet. Sie sollten mit dem regulären Ausdruck experimentieren, indem Sie ein Werkzeug wie Regulator verwenden.

+1

In diesem Fall ist die Prozesszeit unendlich! Und ohne Out of Memory oder Stack Overflow Ausnahme – PierrOz

+0

Es ist durchaus möglich, dass diese Regex nicht abgeschlossen ist. –

-1

Das Problem ist, dass Sie "Schleifen" in Ihrem Regex verschachtelt haben, die es schrecklich ineffizient machen (so dass es aufgrund der Komplexität des Ausdrucks im Grunde ewig dauert).

Wenn Sie sagen, was Sie möchten, kann ich versuchen, eine effizientere Regex dafür herauszufinden.

4

Wenn ich den Ausdruck in RegexBuddy eingeben, zeigt es folgende Meldung

Das Spiel Versuch früh abgebrochen wurde, weil der reguläre Ausdruck zu komplex ist. Die Regex-Engine, die Sie planen, verwenden Sie möglicherweise mit es überhaupt nicht umgehen können und Absturz. Nachschlagen "katastrophale Backtracking" in der Hilfedatei zu lernen, wie diese Situation zu vermeiden .

Looking up katastrophal Rückzieher gibt die folgende Erklärung

Runaway Reguläre Ausdrücke: Katastrophale Backtracking
Betrachten wir den regulären Ausdruck (x + x +) + y. Bevor Sie schreien entsetzt und sagen dieses erfundene Beispiel als xx + y geschrieben sein sollte genau passen die gleiche ohne diese schrecklich verschachtelten quantifiers: einfach mal davon aus, dass jeder „x“ etwas komplexer darstellt, mit bestimmten Zeichenfolge wird von beide "x" abgestimmt. Ein reales Beispiel finden Sie im Abschnitt HTML unten.

Lassen Sie uns sehen, was passiert, wenn Sie diese Regex auf xxxxxxxxxxy anwenden. Die erste x + wird alle 10 x Zeichen übereinstimmen. Die Sekunde x + schlägt fehl. Die erste x + dann Backtracks zu 9 Übereinstimmungen, und die zweite nimmt die verbleibenden x. Die Gruppe hat jetzt einmal abgestimmt. Die Gruppe wiederholt, aber schlägt bei der ersten x + fehl.Da eine Wiederholung ausreichend war, stimmt die Gruppe überein. y passt y und eine Gesamtübereinstimmung ist gefunden. Der Regex wird als funktionsfähig deklariert, der Code wird an den Kunden gesendet, und sein Computer explodiert. Fast.

Der obige Regex wird unschön, wenn die y in der Betreffzeile fehlt. Wenn y fehlschlägt, die Regex-Engine Backtracks. Die Gruppe hat eine Iteration, in die sie zurückgehen kann. Die Sekunde x + stimmte nur ein x, so dass es nicht zurückverfolgen kann. Aber das erste x + kann ein x aufgeben. Die zweite x + prompt entspricht xx. Die Gruppe hat wieder eine Iteration, schlägt die nächste aus, und die y schlägt fehl. Backtracking wieder, die Sekunde x + hat jetzt eine Backtracking Position, reduziert sich auf x anzupassen. Die Gruppe versucht eine zweite Iteration. Der erste x + Treffer, aber der zweite ist am Ende der Zeichenfolge stecken. Backtracking wieder, die erste x + in die erste Iteration der Gruppe reduziert selbst auf 7 Zeichen. Die zweite x + entspricht xxx. Fehlt y, wird die zweite x + auf xx und dann auf x reduziert. Jetzt kann die Gruppe eine zweite Iteration, , mit einem x für jedes x + abgleichen. Aber diese (7,1), (1,1) Kombination scheitert auch. Also geht es zu (6,4) und dann (6,2) (1,1) und dann (6,1), (2,1) und dann (6,1), (1,2) und dann denke ich, dass du startest um die Drift zu bekommen.

Wenn Sie versuchen, diese Regex auf einem 10-fach-String in RegexBuddy des Debuggers, wird es 2558 Schritte unternehmen, um die endgültige y, um herauszufinden, fehlt. Für einen 11x-String benötigt es 5118 Schritte. Für 12 dauert es10238 Schritte. Natürlich haben wir hier eine exponentielle Komplexität von O (2^n). Bei 21x beugt sich der Debugger bei 2,8 Millionen Schritten, Diagnose eines schweren Falles von katastrophalen Backtracking.

RegexBuddy verzeiht, dass er erkennt es im Kreis und bricht das Spiel Versuch. Andere Regex Motoren (wie .NET) wird weiter für immer, während andere mit einen Stapelüberlauf (wie Perl, vor Version 5.10) abstürzen. Stack-Überläufe sind besonders unangenehm auf Windows, seit neigen sie dazu, Ihre Anwendung verschwinden ohne eine Spur oder Erklärung. Seien Sie sehr vorsichtig, wenn Sie einen Webdienst ausführen, der es Benutzern ermöglicht, ihre eigenen regulären Ausdrücke zu liefern. Menschen mit wenig Regex-Erfahrung haben überraschende Fähigkeit, mit exponentiell komplexen regulären Ausdrücke zu kommen.

Ich nehme an, Sie werden es in Code behandeln müssen. Ich schlage vor, Sie kontaktieren den Autor von Regexbuddy und fragen, was benötigt wird, um dieses Szenario zu erkennen.

+1

RegexBuddy verwendet eine eigene Regex-Engine und unterstützt alle wichtigen Regex-Varianten. Meine Schätzung ist, dass es das Nein vorberechnet. der erforderlichen Iterationen/Schritte und bricht die Übereinstimmung ab, wenn diese Anzahl das vom Programm erlaubte Maximum überschreitet. – Cerebrus

+0

von http://en.wikipedia.org/wiki/Regular_expression: "(...) Der dritte Algorithmus soll das Muster gegen die Eingabe-Zeichenfolge durch Backtracking übereinstimmen. Dieser Algorithmus wird häufig als NFA bezeichnet, aber diese Terminologie kann verwirrend sein Seine Laufzeit kann exponentiell sein, was einfache Implementierungen beim Vergleich mit Ausdrücken wie (a | aa) * b zeigen, die sowohl Alternation als auch unbegrenzte Quantifizierung enthalten und den Algorithmus zwingen, eine exponentiell ansteigende Anzahl von Unterfällen zu berücksichtigen.) ". Es muss Teil einer Erklärung sein ... – PierrOz

-1

Scheint mir wie ein Fall der Regex-Match wächst exponentiell. Siehe die BCL blog.

Beste Lösung ist es, eine Zeitüberschreitung für die Regex, keine Unordnung mit Threads festlegen.

Siehe hier wie man strip out strings with timeout.

+0

Problem ist, die Timeout-Funktion wurde erst mit .NET 4.5 eingeführt, und das OP sagte, dass er 3.5 verwendet. –