我有一个带有以下(无效)结构的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子字符串为</tag1>...<tag1>
tag1
(并在封闭的<tag1></*
下移动所有内容)
我尝试过使用sed但没有成功(下面有一个这样的尝试)
sed -e 's/<\/tag1>\(.*\)<tag1><\//\1<\//g'
它适用于上面的示例,但是如果我有两次出现相同的条件,则只删除第一个</tag1>
和最后一个<tag1>
,而不是执行两次替换
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来覆盖最大的选择,但如果我不想让它做这样的事情该怎么办呢?
答案 0 :(得分:1)
你想要非贪婪的匹配,但据我所知,sed并不支持它。你可以使用perl还是必须使用sed?
尝试:perl -p -e 's/<\/tag1>(.*?)<tag1>(\<\/.+?<\/tag1>)/\1\2/g'
我认为问题是正则表达式必须匹配到实际结束时,否则结束标记将成为下一场比赛的开始。
答案 1 :(得分:1)
sed 's|</tag1><tag3>|<tag3>|;s|</tag3><tag1>|</tag3>|' file.xml
输出:
<tag1>text1<tag2>text2<tag3>text3</tag3></tag2>text4</tag1>
答案 2 :(得分:1)
This might work for you (GNU sed):
sed -r 's/<tag1>/\n/g;s/<\/tag1>(<tag3>[^\n]*)\n/\1/g;s/\n/<tag1>/g' file
Reduce <tag1>
to a unique character i.e \n
then use the negated character class [^\n]
to obtain non-greedy matching. Following the changes reverse the initial substitution.
答案 3 :(得分:0)
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 -->
如果看到字符串<tag1></
,则删除第一个</tag1>
和第二个<tag1>