在匹配的子字符串上应用正则表达式

时间:2015-05-08 02:59:22

标签: regex bash awk sed

我有几千条这样的文字行:

go to <CITY>rome</CITY> <COUNTRY>italy</COUNTRY>

我想要的输出是替换从第一个标记词(罗马)到最后一个(意大利)的所有内容并放置标记:

go to <ADDRESS>rome italy</ADDRESS>

我可以匹配标记为的文本行部分:

<.*>

这将贪婪地选择第一个&lt;持续&gt;。我希望删除标签并将<ADDRESS></ADDRESS>放在匹配的部分周围。

可能的标签有:<STREETNUM><STREET><CITY><STATE><ZIP><COUNTRY>。这些标记的任何子集都可以按任何顺序出现。标签永远不会嵌套。

我搜索了SO并用谷歌搜索无济于事。也许我可以使用一个命名的捕获组,然后在其上应用搜索/替换正则表达式,但我不知道如何。任何帮助都会受到赞赏。

1 个答案:

答案 0 :(得分:2)

sed行将执行此操作:

sed 's/<CITY>\(.*\)<\/CITY>.*<COUNTRY>\(.*\)<\/COUNTRY>/<ADDRESS>\1 \2<\/ADDRESS> /g'

例如:

sed 's/<CITY>\(.*\)<\/CITY>.*<COUNTRY>\(.*\)<\/COUNTRY>/<ADDRESS>\1 \2<\/ADDRESS> /g'  <<< "go to <CITY>rome</CITY> <COUNTRY>italy</COUNTRY>"

打印:

go to <ADDRESS>rome italy</ADDRESS> 

它基本上捕获CITY标记内和COUNTRY标记内的内容,然后将其替换为包含ADDRESS标记的捕获组值

如果您正在使用Linux,则可以避免使用(标记转义-E

sed -E 's/<CITY>(.*)<\/CITY>.*<COUNTRY>(.*)<\/COUNTRY>/<ADDRESS>\1 \2<\/ADDRESS> /g'

<强>更新

为了达到预期的效果,您可以按以下操作顺序使用多个命令:

  1. 删除go to文字:sed 's/go to //g'
  2. 删除所有标记字符:tr -d '</>'
  3. 删除所有标记字符后,您可以安全地删除字词STREETNUMSTREETCITYSTATEZIP和{ {1}}来自输入:

    COUNTRY

  4. 获取先前命令连接生成的输出并将其输出到sed -E 's/CITY|COUNTRY|STATE|ZIP|STREETNUM|STREET//g'标记内:

    <ADDRESS></ADDRESS>

  5. 最后的命令如下,xargs -i echo "go to <ADDRESS>{}</ADDRESS>"应该包含要处理的行:

    $LINE

    一个例子:

    运行:

    sed 's/go to //g' <<< "$LINE" | tr -d '</>' | sed -E 's/CITY|COUNTRY|STATE|ZIP|STREETNUM|STREET//g' | xargs -i echo "go to <ADDRESS>{}</ADDRESS>"
    

    将打印:

    sed 's/go to //g' <<< "go to <STATE>Bolivar</STATE> <COUNTRY>Venezuela</COUNTRY> <STREETNUM>5</STREETNUM> " | tr -d '</>' | sed -E 's/CITY|COUNTRY|STATE|ZIP|STREETNUM|STREET//g' | xargs -i echo "go to <ADDRESS>{}</ADDRESS>"