sed 单词重复问题

Mr.*_*ith 3 sed

我是 sed 的新手,正在尝试学习。但是,我在使用 sed 删除重复词时遇到了无法解决的问题:

echo "abc abc def ghi ijk ijk" | sed 's/\([a-z][a-z]*\) \1/\1/g'
Run Code Online (Sandbox Code Playgroud)

产出

abc def ghijk ijk
Run Code Online (Sandbox Code Playgroud)

每当一个单词以与下一个单词的第一个字母相同的字母结尾时,它就会这样做。我究竟做错了什么 ?

Joh*_*024 5

问题在于,正则表达式可以匹配部分单词。在您显示的示例中,它将i一个单词末尾的 与下一个单词i开头的匹配。解决方案是坚持正则表达式匹配整个单词:

$ echo "abc abc def ghi ijk ijk" | sed 's/\<\([a-z][a-z]*\)\> \<\1\>/\1/g'
abc def ghi ijk
Run Code Online (Sandbox Code Playgroud)

在 GNU sed 中,\<匹配单词的开头并\>匹配单词的结尾。

更复杂的比赛

在问题的示例中,正则表达式匹配单个重复字符i i. 这是一个匹配的示例oat oat

$ echo "smoat oats" | sed 's/\([a-z][a-z]*\) \1/\1/g'
smoats
Run Code Online (Sandbox Code Playgroud)

这再次通过坚持整个单词来解决:

$ echo "smoat oats" | sed 's/\<\([a-z][a-z]*\)\> \<\1\>/\1/g'
smoat oats
Run Code Online (Sandbox Code Playgroud)

简化

由于字母到空格的转换总是标记一个单词边界,因此上面使用的正则表达式部分\> \<是不必要的,因为正则表达式要求两边的字符都是字母。因此,我们可以使用:

$ echo "smoat oats" | sed 's/\<\([a-z][a-z]*\) \1\>/\1/g'
smoat oats
Run Code Online (Sandbox Code Playgroud)

文档

有关 sed 及其正则表达式的微妙之处的更多信息,我推荐Grymoire 教程。GNU sed 的最终参考是GNU sed 手册