【问题标题】:Extract text from multiline content using sed使用 sed 从多行内容中提取文本
【发布时间】:2020-07-06 09:50:29
【问题描述】:

如何使用sed(或其他简单方法)提取下例中CDATA之间的内容?

棘手的是模式必须在多行上进行评估,并且行的一部分必须保留在提取的结果中......所以我希望像sedawk这样的强大工具能够使用捕获正则表达式提取文件的内容..没有成功!

内容示例:

<XmlBox className="com.example.ConfigData">
<xmlString><![CDATA[<ConfigData>
<myField>Here we go:

Yup.
</myField>
</ConfigData>]]></xmlString>
</XmlBox>

<XmlBox className="com.example.ServiceDefinition">
<xmlString><![CDATA[<ServiceDefinition>
<name>Tricky?</name>
</ServiceDefinition>]]></xmlString>
</XmlBox>

预期结果:

<ConfigData>
<myField>Here we go:

Yup.
</myField>
</ConfigData>

<ServiceDefinition>
<name>Tricky?</name>
</ServiceDefinition>

捕获它的相关正则表达式是:

(?s)&lt;XmlBox className=".+?"&gt;\s+&lt;xmlString&gt;&lt;!\[CDATA\[(.+?)\]\]&gt;&lt;/xmlString&gt;\s+&lt;/XmlBox&gt;

但是如何在一个简单的 bash 命令中自动化呢? 我以为这很容易,不是吗?

【问题讨论】:

  • 我强烈建议使用旨在处理 xml 的程序来解析 xml。喜欢xlmlintxml_grep
  • 是的,但我不想依赖“有效”的 xml 解析器,这里只需要提取捕获的组,或者在标记之间做子串......没什么大不了的,正确的 ?顺便说一句,这对其他需求很有用,但感谢您的提示。
  • 没什么大不了的。就像parsing html with regex 一样,这是个好主意。
  • 99.999% 我的用例应该在这里工作......所以我不在乎:)

标签: xml bash shell sed


【解决方案1】:

正如 cmets 中提到的,这是一个糟糕的主意。但是,如果你想朝自己的脚开枪:

perl -000 -pe 's/<XmlBox className=".*">\s+<xmlString><\!\[CDATA\[([^]]*)\]\]><\/xmlString>\s*<\/XmlBox>/$1/' input

【讨论】:

  • 请注意,我们也可以使用与提供的完全相同的正则表达式,通过使用perl -00 -pE 's|CAPTURING_REGEXP|$1|' input.xml-E 用于全功能正则表达式,| 用于类似于 sed 的分隔符,不会与正则表达式冲突。伟大的。非常感谢!
【解决方案2】:

另一个非常简单的解决方案:

grep -ozP '(?s)<XmlBox className=".+?">\s+<xmlString><!\[CDATA\[\K.+?(?=\]\]></xmlString>\s+</XmlBox>)' data.xml
  • \K 在最后打印时丢弃先前匹配的字符
  • 正向前瞻(?=matchAfter) 断言匹配必须跟在 matchAfter 表达式之后。

感谢https://stackoverflow.com/a/28060342/1034782

【讨论】:

    【解决方案3】:

    找到的最佳解决方案是使用 Python。

    replace.py 中编写(非常)几行代码:

    #!/usr/bin/python
    import sys, re
    
    # config
    file = sys.argv[1]
    find = sys.argv[2]
    repl = sys.argv[3]
    
    # run
    with open (file, "r") as myfile:
         s=myfile.read()
    print re.sub(find, repl, s)
    

    如下调用:

    ./replace.py input.xml 'CAPTURING_REGEXP' '\1' > output.xml
    ./replace.py input.xml '(?s)<XmlBox className=".+?">\s+<xmlString><!\[CDATA\[(.+?)\]\]></xmlString>\s+</XmlBox>' '\1' > output.xml
    

    它完全做到了它应该做的事情(没有缺点),而且速度惊人(处理一个 750MB 文件需要 10 秒)。

    感谢@kpie answer 的提示。

    【讨论】:

      【解决方案4】:

      Sed 在处理多行数据时很尴尬。正如其他人所提到的,它不是这项工作的好工具,但如果这是您真正想要的,请使用 tr 删除换行符,然后将它们重新添加,例如

      cat myfile | tr '\n' '\007' |sed 's/fromwhatever/towhatever/'
      

      然后使用 tr 将换行符放回原处。在上面的示例中,八进制 7 是一个铃(可能不会出现在您的数据中 - 您可以使用任何尚未出现的字符。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-17
        • 2010-12-13
        • 2015-08-05
        • 2017-01-12
        • 1970-01-01
        • 2013-02-05
        相关资源
        最近更新 更多