我是 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)
每当一个单词以与下一个单词的第一个字母相同的字母结尾时,它就会这样做。我究竟做错了什么 ?
问题在于,正则表达式可以匹配部分单词。在您显示的示例中,它将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 手册。