In einer Nussschale
Es scheint, dass die schnelle Lösung für Ihr Problem darin besteht, ein REGEX oder einen FSA (Finite-State-Automaten) zu definieren, der alle möglichen Anfänge von Dokumenten erkennt (Fehlalarme sind zulässig, die eigentlich keinem Dokument entsprechen würden). Sie können es dann bei Ihrer Eingabe sehr schnell ausführen, um die nächste Stelle zu identifizieren, an der ein Dokument mit wenigen Fehlern beginnen könnte. Es kann einige fehlerhafte Positionen für einen Dokumentstart verursachen, diese werden jedoch vom Parser erkannt und abgebrochen.
So Finite State Automaton kann der Parser Name sein , das Sie gesucht haben. :)
Das Problem
Es ist immer schwierig, ein praktisches Problem zu verstehen, besonders wenn das Vokabular viele Interpretationen hat. Das Wort Parsing Forest wurde (afaik) für das kontextfreie Parsen (CF) mehrdeutiger Sätze mit mehreren Parsingbäumen geprägt. Es kann etwas verallgemeinert werden, um ein Satzgitter oder andere Arten von Grammatik zu analysieren. Daher waren alle Antworten zu Earley, GLR, Marpa und abgeleiteten Parsern (es gibt viele andere) in diesem Fall nicht relevant.
Aber das haben Sie anscheinend nicht im Sinn. Sie möchten eine eindeutige Zeichenfolge analysieren, bei der es sich um eine Folge eindeutiger Dokumente handelt, und einen Analysebaum für jedes Dokument oder eine strukturierte Darstellung abrufen , da Sie nicht genau angeben, wie die Syntax Ihrer Dokumente definiert ist und woher sie stammt eine formale sprachliche Sichtweise. Was Sie haben, sind ein Algorithmus und Tabellen, die den Parsing-Job ausführen, wenn sie am Anfang eines Dokuments gestartet werden. So sei es.
Das eigentliche Problem ist, dass Ihr Dokumentenstrom erheblichen Müll enthält, der die Dokumente voneinander trennt. Und es scheint, dass es Ihre Schwierigkeit ist, diesen Müll schnell genug zu scannen. Ihre derzeitige Technik besteht darin, am Anfang zu beginnen und zu versuchen, ab dem ersten Zeichen zu scannen und beim nächsten Zeichen mit dem Neustart fortzufahren, wenn dies fehlschlägt, bis Sie ein gesamtes Dokument gescannt haben. Anschließend wiederholen Sie die Eingabe ab dem ersten Zeichen nach dem gerade gescannten Dokument.
Dies ist auch die von @amon im zweiten Teil seiner Antwort vorgeschlagene Lösung .
Dies ist möglicherweise keine sehr schnelle Lösung (ich kann sie nicht testen), da es unwahrscheinlich ist, dass der Code des Parsers so optimiert ist, dass er am Anfang eines Dokuments sehr effizient gestartet wird. Bei normaler Verwendung wird dies nur einmal ausgeführt, sodass es aus Optimierungssicht kein Hot Spot ist. Daher ist Ihr mäßiges Glück mit dieser Lösung nicht zu überraschend.
Was Sie also wirklich brauchen, ist ein Algorithmus, der schnell den Anfang eines Dokuments findet, das mit einer Menge Müll beginnt. Und Sie haben Glück: Es gibt solche Algorithmen. Und ich bin mir sicher, dass Sie es wissen: Es heißt Suche nach einer REGEX.
Die einfache Lösung
Sie müssen lediglich die Spezifikation Ihrer Dokumente analysieren, um herauszufinden, wie diese Dokumente beginnen. Ich kann Ihnen nicht genau sagen, wie, da ich nicht sicher bin, wie ihre Syntaxspezifikation formal organisiert ist. Möglicherweise beginnen sie alle mit einem Wort aus einer endlichen Liste, möglicherweise gemischt mit Satzzeichen oder Zahlen. Das müssen Sie überprüfen.
Sie müssen lediglich einen Finite-State-Automaten (FSA) oder für die meisten Programmierer einen regulären Ausdruck (REGEX) definieren, der die ersten Zeichen eines Dokuments erkennt: Je mehr, desto besser, aber nicht unbedingt sehr groß (da dies Zeit und Raum beanspruchen kann). Dies sollte ausgehend von der Spezifikation Ihrer Dokumente relativ einfach zu bewerkstelligen sein und kann wahrscheinlich automatisch mit einem Programm durchgeführt werden, das die Spezifikation Ihrer Dokumente liest.
Sobald Sie Ihren regulären Ausdruck erstellt haben, können Sie ihn in Ihrem Eingabestream ausführen, um wie folgt sehr schnell zum Anfang Ihres ersten (oder nächsten) Dokuments zu gelangen:
Ich nehme an:
- docstart
ist eine Regex, die dem Anfang aller Dokumente entspricht.
- search(regex, stream)
ist eine Funktion, die stream
nach einer passenden Teilzeichenfolge sucht regex
. Wenn er zurückkehrt, wird der Stream ab dem Beginn des ersten übereinstimmenden Teilstrings auf sein Suffix reduziert, oder für den leeren Stream wird keine Übereinstimmung gefunden.
- parse(stream)
Versucht, ein Dokument vom Anfang des Streams zu analysieren (was davon übrig ist), und gibt den Analysebaum in einem beliebigen Format zurück oder schlägt fehl. Bei der Rückkehr wird der Stream an der Position unmittelbar nach dem Ende des analysierten Dokuments auf sein Suffix reduziert. Es ruft eine Ausnahme auf, wenn das Parsen fehlschlägt.
forest = empty_forest
search(docstart, stream)
while stream is not empty:
try:
forest = forest + parse(stream)
except
remove first character from stream
search(docstart, stream)
Beachten Sie, dass das Entfernen des ersten Zeichens erforderlich ist, damit bei der nächsten Suche nicht wieder dieselbe Übereinstimmung gefunden wird.
Natürlich ist die Verkürzung des Streams ein Bild. Es kann nur ein Index für den Stream sein.
Ein letzter Hinweis ist, dass Ihr Regex nicht zu genau sein muss, solange er alle Anfänge erkennt. Wenn gelegentlich eine Zeichenfolge erkannt wird, die nicht der Anfang eines Dokuments sein kann (falsch positiv), sind die Kosten für einen nutzlosen Anruf beim Parser die einzige Strafe.
Das kann also möglicherweise dazu beitragen, den regulären Ausdruck zu vereinfachen, falls dies nützlich ist.
Über die Möglichkeit einer schnelleren Lösung
Die obige Lösung sollte in den meisten Fällen ziemlich gut funktionieren. Wenn Sie jedoch wirklich viel Müll und Terabyte an Dateien zu verarbeiten haben, gibt es möglicherweise andere Algorithmen, die schneller ausgeführt werden.
Die Idee leitet sich aus dem Boyer-Moore-Algorithmus für die Suche nach Zeichenfolgen ab . Dieser Algorithmus kann einen Stream extrem schnell nach einer einzelnen Zeichenfolge durchsuchen, da er eine Strukturanalyse der Zeichenfolge verwendet, um das Lesen des größten Teils des Streams zu überspringen und Fragmente zu überspringen, ohne sie überhaupt anzusehen. Es ist der schnellste Suchalgorithmus für eine einzelne Zeichenfolge.
Die Schwierigkeit besteht darin, dass die Anpassung an reguläre Ausdrücke und nicht an einzelne Zeichenfolgen sehr heikel erscheint und je nach den Funktionen des zu untersuchenden regulären Ausdrucks möglicherweise nicht so gut funktioniert. Dies kann wiederum von der Syntax der zu analysierenden Dokumente abhängen. Aber vertraue mir nicht zu sehr, da ich keine Zeit hatte, die gefundenen Dokumente sorgfältig zu lesen.
Ich überlasse Ihnen ein oder zwei Hinweise, die ich im Internet gefunden habe, darunter einen, der anscheinend ein referiertes Forschungspapier ist , aber Sie sollten dies als spekulativer, möglicherweise als recherchierender Hinweis betrachten, der nur in Betracht gezogen werden sollte, wenn Sie starke Leistungsprobleme hatten. Und es gibt wahrscheinlich kein Regalprogramm, das das macht.