消除跨行重复的单词

时间:2019-02-14 19:04:13

标签: sed

我想要一个sed脚本,该脚本可以消除文本文件中一行或多行上的重复单词。例如:

this is is is a text file file it is littered with duplicate words
words words on one or more lines lines
lines
  lines

应转换为:

this is a text file it is littered with duplicate words
on one or more lines

此awk脚本产生正确的输出:

{
    for (i = 1; i <= NF; i++) {
        word = $i

        if (word != last) {
            if (i < NF) {
                next_word = $(i+1)

                if (word != next_word) {
                    printf("%s ", word)
                }
            } else {
                printf("%s\n", word)
            }
        }
    }

    last = word
}

但是我真的很想要一个sed“单线”。

3 个答案:

答案 0 :(得分:1)

这至少在示例输入中可用于GNU sed:

$ sed -Ez ':a;s/(\<\S+)(\s+)\1\s+/\1\2/g;ta' infile
This is a text file and is littered with duplicate words
on one or more lines

使用-E选项可以避免逃避捕获组括号和+量词。

-z将输入视为空字节分隔,即视为一行。

该命令的结构如下

:a      # label
s///g   # substitution
ta      # jump to label if substitution did something

替换为:

s/(\<\S+)(\s+)\1\s+/\1\2/g
  • 第一个捕获组:(\<\S+) –一个完整的单词(单词边界的开头,一个或多个非空格字符
  • 第二个捕获组:(\s+) –第一个单词后的空格为空白
  • \1\s+ –再次是第一个单词加上其后的空白

这将保留第一个单词后的空白,并删除重复项后的空白。

请注意,-E-z\<\S\s都是POSIX sed的GNU扩展。

答案 1 :(得分:0)

使用sed,您可以使用

sed -E 's/([a-z]+) +\1/\1/g'

请注意,它适用于重复项。不适用于一式三份或换行符。

可以通过连接所有行并循环来解决此问题。

sed -E ':a;N;s/(\b[a-z]+\b)([ \n])[ \n]*\b\1\b */\1\2/g;ba'

答案 2 :(得分:0)

sed -En '
    H
    ${
        g
        s/^\n//
        s/(\<([[:alnum:]]+)[[:space:]]+)(\2([[:space:]]+|$))+/\1/g
        p
    }
' file
This is a text file with duplicate words
on one or more lines

其中

  • H-将每行追加到保留空间
  • ${...}-在最后一行,执行随附的命令
  • g-用保留空间的内容替换模式空间
  • s/^\n//-删除开头的换行符(H在第一行的副作用)
  • s/(\<([[:alnum:]]+)[[:space:]]+)(\2([[:space:]]+|$))+/\1/g
    ..1..2............2............1..........................

    • 这里的关键是分别捕获文本和空格,以便后向引用可以与不同的空白匹配。
    • 捕获的表达式#1是第一个单词,它是空格(可以包含换行符),捕获的表达式#2只是该单词。