2017-02-17 3 views
0

Ich muss etwas Text aus einem PDF-Stream als Zeichenfolge ziehen. Dieser Stream enthält sowohl das Markup zur Beschreibung des Erscheinungsbilds des Textes als auch den Text selbst. Die Zeichenfolge, die ich erhalte, auf der meine Regex ausgeführt werden muss, enthält nie Zeilenumbrüche oder Zeilenvorschübe. Die Textbereiche, an denen ich interessiert bin, befinden sich immer in Klammern (und es wird möglicherweise Klammern in Klammern geben), und nach der letzten Klammer gibt es die Buchstaben "Tj". Kurz gesagt, was ich bin nach wird die Konvention immer folgen:Regex, wo Klammer nicht ausgeglichen sein kann

(.....) Tj 

Im Moment der regex Ich habe funktioniert, solange die Klammer sind alle ausgeglichen:

\((?:[^()]|(?'paren'\()|(?'-paren'\)))+(?(paren)(?!))\) 

Wenn jedoch die Text selbst enthält unausgewogene Parathesis, diese Regex wird nicht ziehen, was ich will, und ich bin mir nicht sicher, wie ich es ändern könnte, um mit unausgeglichenen Klammern umgehen zu können. ‚: Antrag auf Zusatzinformation RE‘ aus, dass:

Hier ist ein Beispiel dessen, was eine ‚normale‘ String betrachtet würde die Zeichenfolge erhalten

q Q /Tx BMC q 0 0 471.34 407.34 re W n BT 1 0 0 1 2 397.16 Tm /Helv 12 Tf 0 g (RE: Request for Additional Information) Tj 

So offensichtlich, was ich will.

und hier ist ein Beispiel Fall, dass meine regex auf (I unausgeglichene Klammern hinzugefügt) fehl:

q Q /Tx BMC q 0 0 471.34 407.34 re W n BT 1 0 0 1 2 397.16 Tm /Helv 12 Tf 0 g (RE: Request for (Additional Information) Tj 0 g 1 0 0 1 2 383.29 Tm 0 g ( 13. Processing TT Instructions -) Audit Note 12) Tj 0 g 1 0 0 1 2 369.42 Tm 0 g () Tj 0 g 1 0 0 1 2 355.55 Tm 0 g (Dear test:) Tj 0 g 1 0 0 1 2 341.68 Tm 0 g () Tj 0 g 1 0 0 1 2 327.8 Tm 0 g (Thank you for the more random words here. )Unfortunately, more words here) terminating (words here) Tj 

Es gibt auch leere Sätze von Klammern in hier, die wie folgt aussehen:

() Tj 

Diese Symbole stellen Wagenrücklauf und Zeilenvorschub dar, wenn das PDF gerendert wird. Jede Hilfe wird geschätzt. Vielen Dank im Voraus.

--- UPDATE Fragen unter

Jede Art von Benutzereingaben beantworten kann zwischen der offenen und schließenden Klammer platziert werden. Ich möchte alle Inhalte wie bereitgestellt extrahieren, wie auch immer das sein mag, auch wenn der Benutzer vergessen hat, seine Klammern auszugleichen. Die einzige Garantie ist, dass der Text zwischen den Klammern eine Benutzereingabe ist, aber wie auch immer sie den Text eingeben, sie folgt also NICHT einem vordefinierten Format wie ([Abkürzung]: [Inhalt]), etc. Die Inhalt wird nur garantiert zwischen einem offenen Parens, einem nahen Parens und nach dem nahen Parens wird die Buchstaben "Tj" sein.

+0

Regelmäßige Ausdrücke können nicht beliebig verschachtelte Klammern verarbeiten. Die Sprache der passenden Klammern ist selbst, nicht regelmäßig. – CollinD

+0

Ich habe Ihre Regex nicht herausgefunden, aber ich habe mit Ihren Beispielen gespielt, und ich denke, dass dies machbar ist, obwohl Sie mehr als nur suchen und ersetzen müssen. Im Beispiel "(RE: Request for (Additional Information)" können Sie "RE: Request for (Zusätzliche Informationen") extrahieren, indem Sie den Anfang der Zeile gefolgt von einer beliebigen Zahl eines anderen Zeichens ersetzen speichern. Der Schlüssel ist, dass. * die längste Übereinstimmung bekommt, so wird es die erste offene Klammer umgehen (RE: ... und gehen Sie den ganzen Weg zu (Zusätzliche ... Ich werde das morgen wieder anschauen. –

+0

Durch die So, in Ihrem Beispiel eines Falls, in dem Ihre Regex fehlschlägt, gibt es mehrere Übereinstimmungen. Werden diese alle auf einer Zeile oder einer pro Zeile sein? –

Antwort

0

Wie ich in einem Kommentar erwähnt habe, kann ich nicht mit .NET helfen, aber ich kann Ihnen einen Ausdruck geben, der helfen könnte. Ich denke, die Lösung erfordert "negative Lookahead", und Perl bietet das. Das Problem ist, dass ich Perl so lange nicht benutzt habe, bis ich vergessen habe, wie ich es durch den gesamten Stream ziehen kann. Wenn ich den Strom in Brocken „(...) Tj“ brechen, die jeweils in einer eigenen Zeile, wird mein Skript auf alle Ihre Beispiele funktionieren:

$ cat pdf_data_line_by_line.txt 
q Q /Tx BMC q 0 0 471.34 407.34 re W n BT 1 0 0 1 2 397.16 Tm /Helv 12 Tf 0 g (RE: Request for Additional Information) Tj 
q Q /Tx BMC q 0 0 471.34 407.34 re W n BT 1 0 0 1 2 397.16 Tm /Helv 12 Tf 0 g (RE: Request for (Additional Information) Tj 
0 g 1 0 0 1 2 383.29 Tm 0 g ( 13. Processing TT Instructions -) Audit Note 12) Tj 
0 g 1 0 0 1 2 369.42 Tm 0 g () Tj 
0 g 1 0 0 1 2 355.55 Tm 0 g (Dear test:) Tj 
0 g 1 0 0 1 2 341.68 Tm 0 g () Tj 
0 g 1 0 0 1 2 327.8 Tm 0 g (Thank you for the more random words here. )Unfortunately, more words here) terminating (words here) Tj 
$ cat get_pdf_text.pl 
#!/usr/bin/perl 
while (<>) { 
    # find some text 
    if (/[^(]*\((?!\)).*\) Tj/) { 
     # strip off leading junk 
     s/[^(]*\((?!\))[ ]*([^)].*)\) Tj/$1/; 
     # output saved part of match 
     print $_; 
     print "YOUR DELIMITER HERE\n"; 
    } 
} 
$ cat pdf_data_line_by_line.txt | ./get_pdf_text.pl 
RE: Request for Additional Information 
YOUR DELIMITER HERE 
RE: Request for (Additional Information 
YOUR DELIMITER HERE 
13. Processing TT Instructions -) Audit Note 12 
YOUR DELIMITER HERE 
Dear test: 
YOUR DELIMITER HERE 
Thank you for the more random words here. )Unfortunately, more words here) terminating (words here 
YOUR DELIMITER HERE 

Allerdings, wenn ich die Beispiele in einen einzigen Strom kombinieren hört es nach dem ersten auf. Ich habe versucht, "g" am Ende des 's' Befehls, aber es hat nicht geholfen:

$ cat pdf_data_single_stream.txt 
q Q /Tx BMC q 0 0 471.34 407.34 re W n BT 1 0 0 1 2 397.16 Tm /Helv 12 Tf 0 g (RE: Request for (Additional Information) Tj 0 g 1 0 0 1 2 383.29 Tm 0 g ( 13. Processing TT Instructions -) Audit Note 12) Tj 0 g 1 0 0 1 2 369.42 Tm 0 g () Tj 0 g 1 0 0 1 2 355.55 Tm 0 g (Dear test:) Tj 0 g 1 0 0 1 2 341.68 Tm 0 g () Tj 0 g 1 0 0 1 2 327.8 Tm 0 g (Thank you for the more random words here. )Unfortunately, more words here) terminating (words here) Tj 
$ cat pdf_data_single_stream.txt | ./get_pdf_text.pl 
RE: Request for (Additional Information) Tj 0 g 1 0 0 1 2 383.29 Tm 0 g ( 13. Processing TT Instructions -) Audit Note 12) Tj 0 g 1 0 0 1 2 369.42 Tm 0 g () Tj 0 g 1 0 0 1 2 355.55 Tm 0 g (Dear test:) Tj 0 g 1 0 0 1 2 341.68 Tm 0 g () Tj 0 g 1 0 0 1 2 327.8 Tm 0 g (Thank you for the more random words here. )Unfortunately, more words here) terminating (words here 
YOUR DELIMITER HERE 

Der Ersatz-String ...

s/[^(]*\((?!\))[ ]*([^)].*)\) Tj/$1/ 

...tut Folgendes: Finden Sie null oder mehr Zeichen, die NICHT '(', gefolgt von einem einzigen '(' das NICHT gefolgt von einem 'ist) (dies ist, wo Sie negative Lookahead brauchen, und dies eliminiert'() Tj 'Fälle), gefolgt von null oder mehr Leerzeichen, dann erinnere {das folgende Zeichen, wenn es kein ')' ist und null oder mehr folgende Zeichen}, gefolgt von einem ') Tj', und ersetze all das durch den gespeicherten String. Wenn jemand den (wahrscheinlich sehr einfachen) Weg vorschlagen kann, das Skript den ganzen Weg durch den Stream zu marschieren, dann sollte das das Problem lösen.

+0

danke für das Absenden Ihrer Antwort. Es hat geklappt, nachdem du dich auf den 'Tj' aufgeteilt hast, um alles in die richtigen Zeilen zu bringen, wie du es oben getan hast. – resu

Verwandte Themen