【问题标题】:How to use sed to fix an xml issue如何使用 sed 修复 xml 问题
【发布时间】:2015-10-02 04:03:04
【问题描述】:

我有一个具有以下(无效)结构的 xml

<tag1>text1<tag2>text2</tag1><tag3>text3</tag3><tag1></tag2>text4</tag1>

我想用sed改成

<tag1>text1<tag2>text2<tag3>text3</tag3></tag2>text4</tag1>

即如果我遇到无效的 xml 子字符串为 &lt;tag1&gt;&lt;/*

我尝试使用 sed 没有成功(下面是这样的尝试)

sed -e 's/<\/tag1>\(.*\)<tag1><\//\1<\//g'

它确实适用于上面的示例,但如果我有两次出现相同的情况,它只会删除第一个 &lt;/tag1&gt; 和最后一个 &lt;tag1&gt;,而不是执行两次替换

echo '<tag1>text1<tag2>text2</tag1><tag3>text3</tag3><tag1></tag2>text4</tag1><tag1>text5<tag4>text6</tag1><tag3>text7</tag3><tag1></tag4>text8</tag1>' | sed -e 's/<\/tag1>\(.*\)<tag1><\//\1<\//g'

输出

<tag1>text1<tag2>text2<tag3>text3</tag3><tag1></tag2>text4</tag1><tag1>text5<tag4>text6</tag1><tag3>text7</tag3></tag4>text8</tag1>

我认为 sed 只是扩展了 RE 以覆盖最大的选择,但是如果我不希望它做这样的事情该怎么办?

【问题讨论】:

  • 让我换个方式问我的问题,下面的算法可以在 sed 中实现吗? 1. 搜索&lt;tag1&gt;&lt;/ 2. 向后搜索第一个&lt;/tag1&gt; 3. 从中间的文本中删除&lt;/tag1&gt;&lt;tag1&gt;
  • 你知道,正确的解决方案是修复产生无效 XML 的过程。
  • 不幸的是,这不是我能拥有的奢侈品。

标签: regex xml sed


【解决方案1】:

您想要非贪婪匹配,但据我所知,sed 不支持它。可以使用 perl 还是必须使用 sed?

试试:perl -p -e 's/&lt;\/tag1&gt;(.*?)&lt;tag1&gt;(\&lt;\/.+?&lt;\/tag1&gt;)/\1\2/g'

我认为问题在于正则表达式必须匹配到实际结束的结尾,否则结束标记将成为下一个匹配的开始。

【讨论】:

  • perl 也不错,其实我不知道这个功能叫做非贪婪匹配,把它加到我的互联网搜索关键字中,我想我已经接近了。我将不得不找到正确的 perl 语法,但至少以下内容不起作用perl -pe 's|&lt;/tag1&gt;(.*?)&lt;tag1&gt;&lt;/|\1&lt;/|g'
  • @JohnBrown - 我更新了我的答案。试一试,如果它不是您想要的,请给我更多细节。
  • @JohnBrown - 另一件事。我不认为你在第二个模式中有两次相同的条件。这是第二组“坏标签”的开始text7text8,没有供正则表达式查找和关闭模式.
  • 您的建议与我在上面的评论中提出的完全一样,但都没有奏效(可能是因为 perl 语法?)。但是你确实有一点,第二组坏标签的条件有点不同,当应用于第二组时,原始替换可能无法按预期工作
  • @JohnBrown 请注意,在我的命令中,我也转义了 。
【解决方案2】:
sed 's|</tag1><tag3>|<tag3>|;s|</tag3><tag1>|</tag3>|' file.xml

输出:

<tag1>text1<tag2>text2<tag3>text3</tag3></tag2>text4</tag1>

【讨论】:

  • 我用了一个简短的例子,tag3 事先不知道,&lt;/tag1&gt;&lt;tag3&gt; 之间可能有额外的文本和/或标签,这个解决方案不起作用
【解决方案3】:

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

sed -r 's/<tag1>/\n/g;s/<\/tag1>(<tag3>[^\n]*)\n/\1/g;s/\n/<tag1>/g' file

&lt;tag1&gt; 减少为唯一字符,即\n,然后使用取反字符类[^\n] 获得非贪婪匹配。更改后会反转初始替换。

【讨论】:

  • 这个解决方案确实适用于我提供的示例,但我的来源也有 \n 这可能会损坏其他部分,尽管我认为这个概念在我的情况下可能会有所帮助,作为最后的手段,我仍然希望我可以通过在 sed 中使用标签/分支的解决方案来学习新的东西
  • 由于 sed 是基于行的,除非您通过 NGHs/../../ 命令引入换行符,因此您的源代码中不能出现换行符。也许您可以详细说明发生这种情况的位置并提供更好的示例。
  • @protong,你对换行是正确的,我真的很喜欢你将复杂的字符串分解成更小的部分以避免处理贪婪/非贪婪选择的方法。我不接受您的回答的原因是它在 RE 部分中有 tag3,我正在处理的实际 XML 非常复杂,唯一已知的信息是 tag1 以及它正在破坏另一个标签的事实,其余的结构可以任意改变。我很确定可以想出一个类似的 RE,它不依赖于 tag1 以外的任何东西。
  • 这是另一个使用potong方法的解决方案,贪婪的行为实际上对我有利,可以找到最后一个&lt;/tag1&gt;sed -e 's|&lt;tag1&gt;&lt;/|\n&lt;/|g;s|\([^\n]*\)&lt;/tag1&gt;\([^\n]*\)\n|\1\2|g'
【解决方案4】:

GNU sed

sed '\,<tag1></,{ s,</tag1>,,; s,<tag1>,,2; }' <<END
<tag1>text1<tag2>text2</tag1><tag3>text3</tag3><tag1></tag2>text4</tag1>  <!-- error case -->
<tag1><tag2 /></tag1><tag1><tag3 /></tag1>                                <!-- should not change -->
END
<tag1>text1<tag2>text2<tag3>text3</tag3></tag2>text4</tag1>  <!-- error case -->
<tag1><tag2 /></tag1><tag1><tag3 /></tag1>                                <!-- should not change -->

如果看到字符串&lt;tag1&gt;&lt;/,则删除第一个&lt;/tag1&gt;和第二个&lt;tag1&gt;

【讨论】:

  • 如果这种情况在同一行中发生了几次,则此解决方案不起作用,并且有点危险,因为它可能会删除正确实例化的 tag1
猜你喜欢
  • 2022-01-22
  • 2012-06-04
  • 2021-03-27
  • 2021-01-21
  • 1970-01-01
  • 2021-04-24
  • 2019-02-16
  • 2014-10-07
  • 2020-08-25
相关资源
最近更新 更多