【问题标题】:Remove lines between patterns nearest another pattern删除最接近另一个图案的图案之间的线条
【发布时间】:2018-12-26 23:14:01
【问题描述】:

我正在尝试从 PDF 文件中删除某些对象。所有的对象都是这样的:

40 0 obj 
<<
/PieceInfo 
/Subtype /Form
/Resources 
<<
/Font 
<<
/Fm1 35 0 R
>>
>>
/Type /XObject
/BBox [0 -22.5 131.05 0]
/Length 601
/Matrix [1 0 0 1 0 0]
>>
stream
  . . .
  A bunch of compressed gibberish here
  . . .
endstream 
endobj

我发现在不破坏 PDF 文档的情况下可以删除 objstreamendstream 之间的内容。

sedawk 中是否有办法查找包含/Form 的行,然后删除上面最近的obj 和下面的stream 之间的所有内容,以及stream 和@987654331 @在它下面,这样最终的结果是这样的:

40 0 obj 
stream
endstream 
endobj

【问题讨论】:

    标签: awk sed


    【解决方案1】:

    给定:

    $ echo "$pdf"
    40 0 obj 
    <<
    /PieceInfo 
    /Subtype /Form
    /Resources 
    <<
    /Font 
    <<
    /Fm1 35 0 R
    >>
    >>
    /Type /XObject
    /BBox [0 -22.5 131.05 0]
    /Length 601
    /Matrix [1 0 0 1 0 0]
    >>
    stream
      . . .
      A bunch of compressed gibberish here
      . . .
    endstream 
    endobj
    

    你可以使用perl:

    $ echo "$pdf" | perl -0777 -lne 'print "$1$2$3\n" if /(^.*(?<=\bobj)\s*\R)[\s\S]*?\/Form[\s\S]*?^(stream\s*^)[\s\S]*?^(endstream\s+endobj)/m'
    40 0 obj 
    stream
    endstream 
    endobj
    

    Demo and explanation of regex

    【讨论】:

    • 我在输出中什么也没得到。也许这是一个perl版本问题?我有v5.22.1
    • @SU3 - 不。这在同一版本下对我有用。这可能与 PDF 中的特殊字符有关,这些字符没有翻译成您在 SO 上发布的输入。
    • 实际上,我使用您发布的文本作为输入进行了检查。
    • @SU3 - 我没有发布它:) 我注意到这会删除所有不属于您的特定删除模式的行。 (echo "hello\n" | perl -0777 -lne 'print "$1$2$3\n" if /(^.*(?&lt;=\bobj)\s*\R)[\s\S]*?\/Form[\s\S]*?^(stream\s*^)[\s\S]*?^(endstream\s+endobj)/m' 不打印)
    • 好吧,echo "hello\n" | ... 是不匹配的,所以没有打印出来。我会告诉您尝试使用 Regex101 上的链接并根据需要进行更改。
    【解决方案2】:
    perl -0777 -pe 's/(?<=obj)[\s\S]+?\/Form[\s\S]+?\n(?=endstream)/\nstream\n/g' pdf
    

    这个正则表达式有很多可能适得其反的方式(关键问题是“obj”或“endstream”出现在中游或那些字段或“/Form”缺失)。你需要一个完整的脚本来保证生产质量,在这种情况下,你肯定需要“展示你的工作”来获得帮助。此外,对于实际的 PDF,您可能需要在 (?=endstream) 之前删除或更改 \n。我不熟悉它使用的行尾字符。

    作为一个整体,jist 会查找obj*/Form*endstream,然后破坏所有不在环视(?[etc]) 中的内容,然后手动读取stream 行。

    【讨论】:

      【解决方案3】:

      awk 也可以完成这项工作,

      awk '/[^end]obj/||/[end]*stream/{print;if(d==1){s=""}d=1;next}{s=s $0}END{print s}' pdf
      

      简要说明,

      1. /[^end]obj/||/[end]*stream/:定位字符串'obj'、'stream'和'endstream'
      2. 如果上述字符串存在于该行中,打印它并启用标志d
      3. 如果d 已启用,请清除缓冲区str
      4. 最后打印str

      【讨论】:

        【解决方案4】:

        这可能对你有用(GNU sed):

        sed -r '/\<obj\>/{n;:a;/\<endobj\>/!{N;ba};s/.*\<(stream)\>.*\<(endobj)\>/\1\n\2/}' file
        

        收集objendobj 之间的线并删除stream 两侧的部分。

        【讨论】:

          【解决方案5】:
          $ cat tst.awk
          $NF == "endobj" {
              print (obj ~ "/Form" ? "stream" ORS "endstream" : obj)
              obj = ""
              inObj = 0
          }
          inObj  { obj = (obj == "" ? "" : obj ORS) $0 }
          !inObj { print }
          $NF == "obj" { inObj = 1 }
          
          $ awk -f tst.awk file
          40 0 obj
          stream
          endstream
          endobj
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-10-28
            • 2014-01-06
            • 2011-03-27
            • 1970-01-01
            • 2018-07-12
            • 2010-11-28
            • 1970-01-01
            相关资源
            最近更新 更多