Was ist der effizienteste Weg zu finden, eine von mehreren Zeichenketten in Python?
Habe ich eine Liste von möglichen Teilstrings, z.B. ['cat', 'Fisch', 'Hund']. In der Praxis enthält die Liste Hunderte von Einträgen.
Ich bin mit der Verarbeitung einer Zeichenfolge, und das, was ich Suche zu finden ist der index des ersten Auftretens von jeder dieser Teilstrings.
Zu klären, für '012cat" das Ergebnis ist 3, und für '0123dog789cat" das Ergebnis ist 4.
Ich muss auch wissen, welche Teilstring gefunden wurde (z.B. den index in der substring-Liste oder der text selbst), oder zumindest die Länge der Teilzeichenfolge übereinstimmt.
Offensichtlichen brute-force-Möglichkeiten, um dies zu erreichen, fragte ich mich, ob es irgendeine elegante Python/Regex-Lösung für dieses.
Dank,
Rax
- Ist die Liste der Zeichenketten-Konstante? Ich Frage deshalb, weil mit Regex-Lösungen beinhalten meist eine Vorberechnung des regulären Ausdrucks (rsp. die Liste der Teilstrings in Ihrem Fall). Wäre das precomputation amortisieren sich über viele suchen?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich würde davon ausgehen, ein regex ist besser als Kontrolle für jeden Teilstring einzeln, weil konzeptionell der reguläre Ausdruck wird modelliert, wie ein DFA, und so, wie die Eingabe verbraucht ist, alle Spiele sind erprobt in der gleichen Zeit (was in einem scan des Eingabe-string).
So, hier ist ein Beispiel:
UPDATE:
Einige Sorgfalt sollte man bei der Kombination von Wörtern in einem einzigen Muster von alternativen Wörtern. Der folgende code erstellt ein regex, aber entweicht alle regex-Sonderzeichen und sortiert die Wörter, so dass auch längere Wörter die chance bekommen, übereinstimmen, bevor eine kürzere Präfixe, die mit dem gleichen Wort:
END UPDATE
Anzumerken, dass Sie wollen, um die form der regex (ie - Aufruf wieder.compile ()), so wenig wie möglich. Im besten Fall werden Sie im Voraus wissen, was Ihr sucht (oder berechnest du Sie einmal/selten) und speichern Sie das Ergebnis erneut.kompilieren irgendwo. Mein Beispiel ist nur ein einfaches Unsinn-Funktion, so dass Sie sehen können, die Verwendung von regex. Es gibt einige weitere regex-docs hier:
http://docs.python.org/library/re.html
Hoffe, das hilft.
UPDATE: ich bin nicht sicher, wie python implementiert reguläre Ausdrücke, aber auf Antwort Rax auf die Frage, ob oder nicht es gibt Grenzen der re.compile() (zum Beispiel, wie viele Wörter können Sie versuchen zu "|" zusammen zu passen auf einmal), und die Zeit, die zum ausführen kompilieren: weder diese scheinen ein Problem zu sein. Ich versuchte diesen code, der gut genug ist, um mich zu überzeugen. (Hätte ich das besser, durch hinzufügen von timing-und reporting-Ergebnisse, sondern wirft auch die Liste der Wörter in einem Satz, um sicherzustellen, gibt es keine Duplikate,... aber beide scheinen diese Verbesserungen wie overkill). Dieser code lief im Grunde sofort, und mich davon überzeugt, dass ich in der Lage bin, um die Suche für die 2000 Worte (Größe 10), und dass und Sie passen entsprechend. Hier ist der code:
UPDATE: Es sollte angemerkt werden, dass die Ordnung der Dinge ORed zusammen in die regex Angelegenheiten. Haben Sie einen Blick auf die folgenden test-inspiriert von TZOTZIOY:
Dieser schlägt vor, die Reihenfolge ist wichtig :-/. Ich bin nicht sicher, was das bedeutet für die Rax-Anwendung, aber zumindest das Verhalten ist bekannt.
UPDATE: ich gepostet diese Fragen über die Implementierung von regulären Ausdrücken in Python die hoffentlich geben uns einen Einblick in die Probleme, die mit dieser Frage.
Ich möchte nur darauf hinweisen, die Zeit Unterschied zwischen DisplacedAussie Antwort und Tom ' s Antwort. Beide waren schnell, wenn einmal verwendet, so sollten Sie nicht haben eine spürbare warten, aber wenn Sie Zeit Ihnen:
Ausgänge:
Ich würde mit Tom ' s Antwort, für die sowohl die Lesbarkeit und Geschwindigkeit.
Dies ist eine vage, theoretische Antwort ohne code zur Verfügung gestellt, aber ich hoffe, Sie können auch zeigen Sie in die richtige Richtung.
Erste, Sie brauchen eine effizientere Suche für Ihre substring Liste. Ich würde empfehlen, irgendeine Art von Struktur. Beginnen Sie mit einem root, fügen Sie ein
'a'
Knoten, wenn alle Zeichenketten beginnen mit'a'
, fügen Sie ein'b'
Knoten, wenn alle Zeichenketten beginnen mit'b'
, und so weiter. Für jeden dieser Knoten, halten Sie das hinzufügen Unterknoten.Zum Beispiel, wenn Sie eine Teilzeichenkette mit dem Wort "Ameise", Sie sollten einen root-Knoten ein Kind-Knoten
'a'
, ein Enkel Knoten'n'
und ein Urenkel Knoten't'
.Knoten sollte einfach genug zu machen.
wo
name
ist ein Zeichen.Durchlaufen Ihre strings Buchstabe für Buchstabe. Verfolgen Sie die Buchstaben, die Sie sind auf. Bei jedem Brief, versuchen Sie den nächsten Buchstaben zum Durchlaufen des Baumes. Wenn Sie erfolgreich sind, wird Ihr Brief-Nummer wird die position des Teilstrings, und Ihre Uberwindung, um zeigen, wird der Teilstring gefunden wurde.
Klärung edit: DFAs sollte sehr viel schneller als diese Methode, und so sollte ich zu eigen Tom ' s Antwort. Ich bin nur halten diese Antwort, falls deine substring-Liste ändert sich oft, in diesem Fall mit einem Baum könnte schneller sein.
Zunächst, ich würde vorschlagen, Sie zum Sortieren der Liste in aufsteigender Reihenfolge. Da mit dem Scannen für einen kürzeren substring schneller ist, dass das Scannen für eine längere substring.
Wie über diese.
Offensichtlich, Sie könnten wieder etwas anderes als ein Tupel.
Diese Werke von: