括号可能不平衡的正则表达式

regex where parenthesis might not be balanced

我必须从 PDF 流中提取一些文本作为字符串。此流将包含描述文本外观的标记和文本本身。我收到的我的正则表达式必须 运行 的字符串永远不会包含任何回车 returns 或换行符。我感兴趣的文本区域将始终在括号内(并且可能在括号内有括号),并且在最后一个括号之后会有字母 'Tj'。总之,我所追求的总是遵循惯例:

(.....) Tj

目前,只要括号全部平衡,我的正则表达式就可以工作:

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

但是,如果文本本身包含不平衡的括号,则此正则表达式将无法满足我的要求,而且我不确定如何更改它才能处理不平衡的括号。

这是一个被认为是 'normal' 字符串的示例:

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

很明显,我想从中获取字符串 'RE: Request for Additional Information'。

这是我的正则表达式失败的示例(我添加了不平衡的括号):

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  

这里还有空括号,看起来像:

() Tj

这些表示呈现 PDF 时的回车 returns 和换行。任何帮助表示赞赏。提前谢谢你。

---更新以回答以下问题

任何类型的用户输入都可以放在左括号和右括号之间。我想按照提供的方式提取所有内容,即使用户忘记平衡他们的括号也是如此。唯一的保证是括号之间的文本是用户输入的,但是他们输入的文本取决于他们,因此它不遵循预定义的格式,例如 ([abbrev]: [content]),等。内容只保证在一个开括号,一个闭括号之间,闭括号之后是字母'Tj'.

正如我在评论中提到的,我无法帮助您解决 .NET 问题,但我可以给您一个可能有帮助的表达方式。我认为该解决方案需要 "negative lookahead",而 perl 提供了这一点。问题是我太久没有使用 perl 了,我忘记了如何让它在整个流中运行。如果我将流分成“(...) Tj”块,每块单独一行,我的脚本将适用于您的所有示例:

$ 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//;
      # 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

但是,如果我将示例组合成一个流,它会在第一个流之后停止。我尝试在 's' 命令末尾使用 "g",但没有帮助:

$ 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

替换字符串...

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

... 执行以下操作:找到零个或多个不是“(”的字符,后跟单个“(”,后跟一个“)”(这是您需要否定前瞻的地方,并且这消除了 '() Tj' 的情况),后跟零个或多个空格,然后记住 {如果后面的字符不是 ')' 和零个或多个后续字符},如果后面跟着 ') Tj',和用记住的字符串替换所有这些。 如果有人可以建议(可能非常简单)让脚本在整个流中运行的方法,那么这应该可以解决手头的问题。