Устранить повторяющиеся слова через строки - PullRequest
0 голосов
/ 14 февраля 2019

Я бы хотел сценарий 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 голосов
/ 14 февраля 2019

Это работает с 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 являются расширениями GNU для POSIX sed.

0 голосов
/ 14 февраля 2019
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 - это просто слово.
0 голосов
/ 14 февраля 2019

С помощью 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'

...