warum python regex ist so langsam?

Nach langem Debuggen habe ich herausgefunden, warum meine Anwendung mit python regexps langsam ist. Hier ist etwas finde ich überraschend:

import datetime
import re

pattern = re.compile('(.*)sol(.*)')

lst = ["ciao mandi "*10000 + "sol " + "ciao mandi "*10000,
       "ciao mandi "*1000 + "sal " + "ciao mandi "*1000]
for s in lst:
    print "string len", len(s)
    start = datetime.datetime.now()
    re.findall(pattern,s)
    print "time spent", datetime.datetime.now() - start
    print

Die Ausgabe auf meinem Rechner ist:

string len 220004
time spent 0:00:00.002844

string len 22004
time spent 0:00:05.339580

Den ersten test-string ist 220K lange, übereinstimmt und die Abstimmung ist Recht schnell. Die zweite test-string ist 20Km lang, passt nicht und es dauert 5 Sekunden zu berechnen!

Wusste ich, dass dieser Bericht http://swtch.com/~rsc/regexp/regexp1.html, die besagt, dass die regexp-Implementierung in python, perl, ruby ist etwas nicht optimal... das Ist der Grund? Ich hätte nicht gedacht, dass es passieren könnte, mit einem so einfachen Ausdruck.

Hinzugefügt
Meine ursprüngliche Aufgabe ist das aufteilen einer Zeichenfolge zu versuchen, verschiedene regex wiederum. So etwas wie:

for regex in ['(.*)sol(.*)', '\emph{([^{}])*)}(.*)', .... ]:
    lst = re.findall(regex, text) 
    if lst:
        assert len(lst) == 1
        assert len(lst[0]) == 2
        return lst[0]

Dies ist zu erklären, warum ich nicht verwenden split. Ich habe mein Problem gelöst durch Austausch (.*)sol(.*) mit (.*?)sol(.*) wie vorgeschlagen, durch Martijn.

Wahrscheinlich sollte ich verwenden match statt findall... aber ich glaube nicht, das hätte das Problem gelöst, da die regexp wird, um übereinstimmung im gesamten Eingangs-und daher findall sollten aufhören, auf den ersten match.

Trotzdem meine Frage war mehr wie einfach ist es, zu fallen in diesem problem für Sie ein regexp-Neuling... ich denke, es ist nicht so einfach zu verstehen, dass (.*?)sol(.*) ist die Lösung (und zum Beispiel (.*?)sol(.*?) ist nicht).

  • Nein, der Grund ist nicht die Implementierung. Der Grund dafür ist, dass die beiden .* sind zu nachsichtig und zu einer katastrophalen backtracking. Was Sie genau versuchen zu tun?
  • die katastrophale backtracking ist die Umsetzung problem. Lesen Sie den verlinkten Artikel von Emanuele.
  • Nein, die katastrophalen backtracking ist in diesem Fall aufgrund der Muster Konzeption. Sie erhalten mehr oder weniger das gleiche Resultat mit anderen NFA-Motoren.
  • Lesen Sie den Artikel. "Die anderen NFA-engines" haben die gleiche Umsetzung. Ein echter FSA würde ohne backtracking.
  • Noch eine Anmerkung: das problem ist nicht verursacht durch die doppelte (.*). Suche für (.*)sol hat genau die gleiche Zeit-Profil. In der Tat (.*)sol ist eigentlich noch schlimmer, wenn der string enthält sol und suchen Sie mit findall(), denn es löst ein gescheiterter backtracking-Suche auf dem Teilstring, der folgt sol. (Die original RE konsumieren werden, wird der gesamte string auf Erfolg).
  • Ich hatte das gleiche Langsamkeit problem - warteten mehr als 2 Minuten, als der string war sehr lang. Ich installiert das Paket regex - funktioniert Super! bekam das Ergebnis sofort für die gleiche Zeichenfolge. Heruntergeladen von hier: pypi.python.org/pypi/regex

Schreibe einen Kommentar