用于捕获最小组的正则表达式

时间:2017-07-12 13:21:14

标签: php regex

我正在尝试捕获PDF Page 对象的ID,如下所示:

4 0 obj
<<
/Type /Page /
...
>>
endobj

ID是' ID 0 obj'。问题是我的文件有多个对象,因此以下模式从第一个对象声明捕获到 Page 对象的第一个实例:

preg_match_all("/([0-9]+) 0 obj.+?\/Page[ \n]*?\//s", $input_lines, output_array);

以下是我的文件示例,如果您想尝试一下,您会看到包含“Page”一词的多个对象:

%PDF-1.3
%¦¦¦¦

1 0 obj
<<
/Type /Catalog /AcroForm << /Fields [12 0 R 13 0 R] /NeedAppearances false  /SigFlags 3 /Version /1.7 /Pages 3 0 R /Names << >> /ViewerPreferences << /Direction /L2R >> /PageLayout /SinglePage /PageMode /UseNone /OpenAction [0 0 R /FitH null] /DR << /Font << /F1 14 0 R >> >> /DA (/F1 0 Tf 0 g) /Q 0 >> /Perms << /DocMDP 11 0 R >>
/Outlines 2 0 R
/Pages 3 0 R
>>
endobj

2 0 obj
<<
/Type /Outlines
/Count 0
>>
endobj

3 0 obj
<<
/Type /Pages
/Count 2
/Kids [ 4 0 R 6 0 R ]
>>
endobj

4 0 obj
<<
/Type /Page
/Parent 3 0 R
/Resources <<
/Font <<
/F1 9 0 R
>>
/ProcSet 8 0 R
>>
/MediaBox [0 0 612.0000 792.0000]
/Contents 5 0 R
>>
endobj

5 0 obj
<< /Length 1074 >>
stream
2 J
BT
0 0 0 rg
/F1 0027 Tf
57.3750 722.2800 Td
( A Simple PDF File ) Tj
ET
BT
/F1 0010 Tf

我应该改变什么才能让它变得贪婪?

编辑:澄清

  • 我忘了提到我需要捕获所有 Page 对象ID。
  • 正如有些人告诉我使用更具体的正则表达式,我不得不说这不是一个关于如何构建对象的正式例子,这也是可能的。您可以看到这些空格不是修饰的,并且在页面'/类型/页面'标记之前可以有多个标记。

示例:

4 0 obj
<< /UselessTag/Type/Page/
...
>>
endobj
  • 有一些名为页面 PageLayout SiglePage 的标签,我不想捕获它们。

6 个答案:

答案 0 :(得分:1)

您可以使用

'~^(\d+) 0 obj(?:(?!^\d+ 0 obj$).)*?\/Type\s*\/Page\s.*?endobj$~sm'

请参阅regex demo

<强>详情:

  • ^ - 行锚点的开头(m修饰符使^匹配行的开头而不是整个字符串的开头)
  • (\d+) 0 obj - 一个或多个数字(捕获到第1组),然后是空格,0,空格和obj子字符串
  • (?:(?!^\d+ 0 obj$).)*? - tempered greedy token匹配任何未启动.模式的字符(^\d+ 0 obj$),尽可能少
  • \/Type\s*\/Page\s - /Type,0 +空格(将\s替换为\h仅匹配水平空格),/Page然后是空白
  • .*? - 在第一次出现
  • 之前尽可能少的0个字符
  • endobj - endobj后跟......
  • $ - 行尾位置。

答案 1 :(得分:0)

你可以在特定的量词中加入一个不合格的问号:

示例:

 \(.*\)

匹配

测试(测试)测试(测试)测试(测试)测试

示例:

 \(.*?\)

匹配

测试(测试)测试(测试)测试(测试)测试

答案 2 :(得分:0)

尝试更具体的正则表达式,使其与文本中不需要的部分不匹配。

preg_match_all("/([0-9]+?) 0 obj\n\<\<\n\/Type\s\/Page[ \n]*?\//s", $input_lines, output_array);

证明:https://regex101.com/r/HjyQpS/1

答案 3 :(得分:0)

这应该有效:

(\d+) 0 obj[^>]+/Page$

Regex101 demo

答案 4 :(得分:0)

我不会在PDF上使用正则表达式。有几个条件,这种方法将失败。

  1. 页面对象位于对象流中(因此打包,很可能是通过Deflate算法)(PDF 1.5及以上版本允许)
  2. PDF文档中的增量更新可能导致同一页面上的双击
  3. 标记/页面不在您想要匹配的字典中,但在间接对象内(从未见过,但理论上可行)。例如,你有:
  4. 5 0 obj
    << /Type 6 0 R ....>>
    endobj     
    6 0 obj
    /Page
    endobj
    

    注意:您也不能指望每个页面都按照pdf文档中的顺序编写,就像您在查看器中看到的一样。

    但是如果你真的必须这样做,我首先要将pdf对象与

    匹配
      

    /([0-9] +)0 obj(。+?)endobj /

    并将在第二个匹配的字符串中搜索

      

    //类型\ S * \页[\ S取代;] /

    &gt;的可选匹配;最后很重要,因为您还需要能够匹配&#34; / Type / Page&gt;&gt;&#34;,其中/ Type / Page是pdf词典中的最后一个条目。

答案 5 :(得分:0)

使用此正则表达式:

/\d+\s0\sobj.+endobj/smU

请注意,修饰符U使匹配变得非贪婪。请参阅此处的匹配示例:https://www.tinywebhut.com/regex/8