2 Stimmen

Regex-Abgleich sehr langsam

Ich versuche, ein PDF zu analysieren, um den Text daraus zu extrahieren (bitte schlagen Sie keine Bibliotheken vor, um dies zu tun, da dies Teil des Lernens des Formats ist).
Ich habe sie bereits deflationiert, um sie in das alphanumerische Format zu bringen. Jetzt muss ich den Text aus den Textblöcken extrahieren.
Mein derzeitiges Muster ist also BT.*?\((.*?)\).*?ET (mit gesetztem DOTMATCHALL), um etwas zu finden wie:

BT
   /F13 12 Tf
   288 720 Td
   (ABC) Tj
ET

Das Einzige, was ich will, ist der Text ABC in den Klammern.
Der obige Text ist nur so formatiert, um ihn zu verdeutlichen. Im deflationierten Text kann alles in einer Zeile stehen, muss aber nicht. Es gibt keine Garantie dafür, dass das BT/ET am Anfang einer Zeile steht. Es kann Leerzeichen und Text vor/nach dem eingeklammerten Abschnitt geben, es kann aber auch nicht sein. Es gibt jedoch nur einen eingeklammerten Abschnitt pro BT/ET-Block.

Das obige Muster funktioniert, ist aber sehr langsam. Ich nehme an, dass es daran liegt, dass die Regex-Bibliothek das Muster, das mit dem Text zwischen BT und (ABC) übereinstimmt, nicht viele Male findet.
Die Regex ist vorkompiliert, um sie zu beschleunigen, aber das scheint vernachlässigbar zu sein.

Wie kann ich das beschleunigen?

0 Stimmen

Ich glaube, Ihre Regex ist falsch formatiert. Versuchen Sie, sie in Backticks zu setzen (`foo`) und sehen Sie, ob sie korrekt angezeigt wird.

0 Stimmen

Und welche Sprache verwenden Sie? Regex hat viele Varianten.

0 Stimmen

Sie ist mit einem Backtick versehen. Der Parser ist die Implementierung von Python.

4voto

Jay Punkte 53725

Wie viele dieser Blöcke können in einem Dokument vorkommen?

Oft ist eine langsame Regex-Ausführung das Ergebnis eines katastrophalen Backtrackings, wie hier beschrieben: http://www.regular-expressions.info/catastrophic.html

Ich weiß nicht, welche Regex-Technologie Sie verwenden, aber Sie könnten versuchen, Lookaround Assertions zu verwenden, wie hier beschrieben: http://www.regular-expressions.info/lookaround.html

Damit können Sie zunächst nur das finden, was Sie wollen, ABC innerhalb von Klammern, und überprüfen Sie dann, ob ihm ein Wert vorangestellt ist und ein anderer Wert folgt.

1voto

bot403 Punkte 2083

Sind Sie sicher, dass die Regex korrekt ist und ABC als Treffer herauszieht? Um welche Sprache handelt es sich bei der Regex-Engine? Die Verwendung meines Debuggers für reguläre Ausdrücke zeigt dies:

"BT.*?((.*?)).*?ET" nicht das ABC heraus, sondern muss die Zeichenfolge "ET" finden und dann zurückgehen, um alles andere zu finden.

"BT.*?\\((.*?)\\).*?ET" funktioniert wie erwartet mit einem einzigen Durchgang von links nach rechts.

0voto

mark stephens Punkte 429

Sie können die PDF-Datei nicht einfach mit einem Regex parsen, um den Text zu extrahieren. In den meisten Fällen ist der Text in komprimierten binären Blobs enthalten oder verschlüsselt. Eine PDF-Datei, in der der Text so angezeigt wird, ist eher die Ausnahme.

0voto

Alan Moore Punkte 70949

Es gibt nicht wirklich genug Informationen für eine eindeutige Antwort - oder vielleicht gehen Sie davon aus, dass wir mehr über PDF wissen als Sie selbst. Gibt es immer eingeklammerte Abschnitte innerhalb dieser BT...ET Abschnitte? Gibt es immer nur einen von ihnen? Ist die BT o ET immer am Anfang einer Zeile? Wenn ja, würde ich vorschlagen

(?m)^BT[^()]*\((.*?)\)[^()]*?^ET

Wenn ich wüsste, wie PDF wörtliche Klammern darstellt, könnte ich mir wahrscheinlich etwas Effizienteres einfallen lassen.

EDIT: Nach der PDF-Spezifikation müssen wörtliche Klammern mit einem Backslash maskiert werden, und es gibt eine Reihe weiterer Backslash-Esccape-Sequenzen. Versuchen Sie also dies:

(?s)\bBT\b[^()]*\(((?:[^()\\]*(?:\\.[^()\\]*)*))\)

Dieser Teil [^()\\]*(?:\\.[^()\\]*)* -entspricht einem Textblock, der escapte Zeichen (einschließlich Parens) enthalten kann, aber keine unescapten Parens. Ich weiß, es sieht hässlich aus, aber es ist der effizienteste Weg, da Python keine atomaren Gruppen oder Possessivquantoren unterstützt.

(?s) ermöglicht . um Zeilenumbrüche abzugleichen, und \bBT\b stellt sicher, dass die BT nicht Teil eines längeren "Wortes" ist. Ich bin einigermaßen zuversichtlich, dass dies alles ist, was ich brauche, um den gesamten Textinhalt abzugleichen, also mache ich mir nicht die Mühe, das Zeug nach dem schließenden Paren abzugleichen.

0voto

ghostdog74 Punkte 305138

Hier ist eine ohne regex. einfache String-Parsing mit Python internals.

>>> xtract="""
... BT
...    /F13 12 Tf
...    288 720 Td
...    (ABC) Tj
... ET
...
... """
>>> for chunk in xtract.split("ET"):
...     if "BT" in chunk:
...         for brace in chunk.split(")"):
...             if "(" in brace:
...                  print brace[brace.find("(")+1:]
...
ABC

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X