使用 Awk 删除重复的 XML 标签?

Remove duplicate XML tags with Awk?

我有一个很长的自定义 XML,在我可以在 BASH 脚本中处理之前需要解决一些问题。

自定义 XML 看起来像这样:

<SOME TAGS>
<a:t>The cat</a:t>
<a:t> is</a:t>
<a:t> very</a:t>
<a:t> cute</a:t>
<SOME OTHER TAGS>
<a:t>the </a:t>
<a:t>dog </a:t>
<a:t>is </a:t>
<a:t>also </a:t>
<a:t>very </a:t>
<a:t></a:t>
<a:t>cute and nice</a:t>
<ANOTHER TAG>

这就是我想要得到的:

<SOME TAGS>
<a:t>The cat is very cute</a:t>
<SOME OTHER TAGS>
<a:t>the dog is also very cute and nice</a:t>
<ANOTHER TAG>

我尝试在第一个 上使用带有 grep 的循环,然后使用 sed 删除额外的标签,但这显然行不通。

是否可以这样做(可能使用 Awk)?

提前谢谢你,

如果您的 XML 是 字面上 这个正则,应该很容易。在 XML 上使用正则表达式和面向行的工具的问题是 XML 语法允许换行符和空格有很多变化;但如果您的输入没有那个,类似下面的内容应该可以工作。

awk '/^<a:t>/ {
    sub(/^<a:t> */, ""); sub(/ *<\/a:t>/, "");
    sent = (sent ? sent " " : "<a:t>") [=10=]
    next }
sent { print sent "</a:t>"; sent="" }
1
END { if(sent) print sent "</a:t>" }' file.xml

我们将当前句子收集到字符串变量sent,然后当我们看到一个与句子标签不同的标签时,或者当我们到达输入文件的末尾时打印出来。

在END块中重复打印是没有吸引力的,但我懒得回去重构了。

演示:https://ideone.com/B8SHOG

对于 perl,假设 <a:t>...</a:t> 总是在他们自己的行上,没有其他文本。由于整个输入都被吞噬了,这对于非常大的文件来说不是一个好的解决方案。

$ perl -0777 -pe 's%(^<a:t>.*</a:t>\n)+%$&=~s#(?<!\A)<a:t>|</a:t>\n(?!\z)##rg%gme' ip.txt 
<SOME TAGS>
<a:t>The cat is very cute</a:t>
<SOME OTHER TAGS>
<a:t>the dog is also very cute and nice</a:t>
<ANOTHER TAG>
  • -0777 吞噬整个输入
  • (^<a:t>.*</a:t>\n)+ 匹配一个或多个以 <a:t> 开头并以 </a:t> 结尾的行(. 不会匹配没有 s 标志的换行符)
    • (?<!\A)<a:t>|</a:t>\n(?!\z) 将匹配 <a:t></a:t> 除了 start/end 匹配字符串
  • e 标志允许在替换部分使用 Perl 代码,此处用于执行另一个替换
  • m 标志允许 ^ 在每一行的开头匹配