Nach dem gestrigen StackOverflow-Ausfall - ist der Abgleich regulärer Ausdrücke wirklich schwierig oder ist die Implementierung einfach ineffizient?


8

Gestern war StackOverflow eine halbe Stunde lang nicht verfügbar. Später schrieben sie einen Blog-Beitrag darüber , in dem sie ausführlich darlegten, dass das Problem auf eine unerwartet hohe Komplexität des Abgleichs regulärer Ausdrücke zurückzuführen sei.

Kurz gesagt, der reguläre Ausdruck a+bwird beim Ausführen der Zeichenfolge aaaaaaaaaaaaaacin der Zeit wobei die Anzahl der Zeichen ist, da Backtracking verwendet wird.Ö(n2)na

Sie können das Problem mit dem folgenden Python-Code reproduzieren, dessen Ausführung auf meinem Computer mehr als 4 Sekunden dauert:

import re, time
start = time.time()
re.findall(r'\s+$', ' '*20000 + 'x')
print(time.time() - start)

Das war sehr überraschend für mich; Ich hätte gedacht, dass ein Regex-Matcher effizienter arbeitet, z. B. indem er einen DFA aus dem Regex erstellt und dann die gewünschte Zeichenfolge durchläuft, was ich für (ohne die DFA-Konstruktion).Ö(n)

(Zum Beispiel geht das Buch Einführung in Algorithmen von Cormen, Leiserson, Rivest einen ähnlichen Algorithmus auf dem Weg zur Einführung des Knuth-Morris-Pratt-Algorithmus durch).

Meine Frage: Gibt es etwas inhärent Schwieriges beim Abgleichen regulärer Ausdrücke, das keinen -Algorithmus zulässtÖ(n) , oder sprechen wir einfach von einer ineffizienten Implementierung (in Python, in was auch immer StackOverflow verwendet, usw.)?


2
Es gibt einen Artikel darüber. Ich denke, es ist hier, aber der Server ist zum Zeitpunkt des Schreibens ausgefallen. Die Zusammenfassung lautet: Ja, wenn Sie nur wörtliche reguläre Ausdrücke wie den, der das Problem hier verursacht hat, verwenden, können Sie in linearer Zeit übereinstimmen, indem Sie zu einem Automaten kompilieren. Bei interpretierten Sprachen müssen Sie jedoch die Zeit berücksichtigen Die Zusammenstellung dauert und wenn es sich wirklich lohnt, das zu tun.
David Richerby

Kann dieser Regex umgeschrieben werden, um schneller zu werden? Ich meine, muss man wirklich auf Substr-Funktionen gehen oder kann er sich einfach einen besseren Regex ausdenken? Ich spreche genau über dieses / \ s + $ / on ("" * 20000) + "x"
Nakilon

Antworten:


8

Wenn Sie nur reguläre Ausdrücke analysieren wollten, hätten Sie solche Probleme nicht (es sei denn, Sie wären ein wirklich inkompetenter Programmierer, denke ich). Vorsichtsmaßnahmen umfassen die Zeit, die zum Erstellen eines Automaten benötigt wird. Ein asymptotisch schlechterer Algorithmus kann in der Praxis in vielen Fällen den Automatenansatz übertreffen.

Das eigentliche Problem ist wahrscheinlich , dass sie mit Bibliotheksfunktionen , die Angebote zu bekommen regexps , die Art und Weise mächtiger als einfache reguläre Ausdrücke. Funktionen wie übereinstimmende Gruppen führen zu einer weiteren Komplexität.

In diesem Fall traten Probleme auf, weil diese Engines mit Teilzeichenfolgen übereinstimmen (mit einfachen regulären Ausdrücken stimmen wir normalerweise nur mit ganzen Eingaben überein) und Backtracking verwenden . lange Teilübereinstimmungen, die schließlich nicht übereinstimmen, verursachen lange Rückverfolgungen. Im Wesentlichen ist dies der schlechteste Fall für einen naiven String-Matching mit quadratischer Zeit.

Kann das verbessert werden? Könnte sein. Unter Verwendung der Ideen aus String-Matching-Automaten würden wir nicht zum zweiten Symbol zurückkehren, sondern zum Anfang des längsten Suffix, das einem Präfix des Musters entspricht. Aber da das Muster nicht mehr festgelegt ist, ist es sicherlich nicht trivial, die Ideen zu erweitern.

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.