Удаление последовательных повторяющихся слов из файла с помощью awk или sed

Удаление последовательных повторяющихся слов из файла с помощью awk или sed

21.01.2020 07:22:24 Просмотров 19 Источник

Мой входной файл выглядит следующим образом:

“true true, rohith Rohith;
cold burn, and fact and fact good good?”

Выходные данные должны выглядеть:

"true, rohith Rohith;
cold burn, and fact and fact good?"

я пытаюсь то же самое с awk, но не смог получить желаемого результата.

awk '{for (i=1;i<=NF;i++) if (!a[$i]++) printf("%s ",$i,FS)}{printf("\n")}' input.txt

Кто-нибудь, пожалуйста, помогите мне здесь.

С уважением, Оптимизации памяти вашего устройства

У вопроса есть решение - Посмотреть?

https://stackoverflow.com/questions/59845282/remove-consecutive-duplicate-words-from-a-file-using-awk-or-sed#comment105825005_59845282
Что представляет собой дубликат?
https://stackoverflow.com/questions/59845282/remove-consecutive-duplicate-words-from-a-file-using-awk-or-sed#comment105825006_59845282
Нет никакого способа использовать uniq на "словах". Вы должны были бы иметь слова на отдельных строках.
https://stackoverflow.com/questions/59845282/remove-consecutive-duplicate-words-from-a-file-using-awk-or-sed#comment105825701_59845282
А как насчет пар, разделенных новой линией? Будут ли они заменены?

Ответы - Удаление последовательных повторяющихся слов из файла с помощью awk или sed / Remove consecutive duplicate words from a file using awk or sed

anubhava

21.01.2020 07:51:20

Это не совсем то, что вы показали в выводе, но близко к использованию gnu-awk:

awk -v RS='[^-_[:alnum:]]+' '$1 == p{printf "%s", RT; next} {p=$1; ORS=RT} 1' file

“true , rohith Rohith;
cold burn, and fact and fact good ?”
Marcelo Castro

21.01.2020 08:06:57

В зависимости от вашего ожидаемого вклада, это может сработать:

sed -r 's/([a-zA-Z0-9_-]+)( *)\1/\1\2/g ; s/ ([.,;:])/\1/g ; s/  / /g' myfile

([a-zA-Z0-9_ -]+) = слова, которые могут повторяться.

(*) \1 = Проверьте, повторяется ли предыдущее слово после пробела.

с/ ([.,;:]) /\1/g = удаляет лишние пробелы перед пунктуацией (возможно, вы захотите добавить символы в эту группу).

s / / / g = удаляет двойные пробелы.

Это работает с GNU sed.

Является ответом!
Ed Morton

21.01.2020 08:20:48

С GNU awk для 4-го arg, чтобы разделить():

$ cat tst.awk
{
    n = split($0,words,/[^[:alpha:]]+/,seps)
    prev = ""
    for (i=1; i<=n; i++) {
        word = words[i]
        if (word != prev) {
            printf "%s%s", seps[i-1], word
        }
        prev = word
    }
    print ""
}

$ awk -f tst.awk file
“true, rohith Rohith;
cold burn, and fact and fact good?”
https://stackoverflow.com/questions/59845282/remove-consecutive-duplicate-words-from-a-file-using-awk-or-sed/59846221#comment105826839_59846221
Это выдающееся использование "seps" в split(). Очень умный.
KamilCuk

21.01.2020 08:24:36

Просто сопоставьте ту же обратную связь в sed:

sed ':l; s/\(^\|[^[:alpha:]]\)\([[:alpha:]]\{1,\}\)[^[:alpha:]]\{1,\}\2\($\|[^[:alpha:]]\)/\1\2\3/g; tl'

Как это работает:

  • :l-создайте метку lдля перехода. Смотрите tlниже.
  • s-замена
    • /
    • \(^\|[^[:alpha:]]\)- совпадение начала строки или неалфавитного символа. Это делается для того, чтобы следующая часть соответствовала всему слову, а не только суффиксу.
    • \([[:alpha:]]\{1,\}\)- сопоставьте слово - один или несколько буквенных символов.
    • [^[:alpha:]]\{1,\}- сопоставьте не-слово-один или несколько не-буквенных символов.
    • \2-соответствует тому же, что и во втором \(...\)- т. е. соответствуй слову.
    • \($\|[^[:alpha:]]\) - соответствует концу строки или соответствовать неалфавитный символ. То есть так мы сопоставляем все второе слово, а не только его приставку.
    • /
    • \1\2\3 - заменить его на <beginning of the line or non-alphabetic prefix character><the word><end of the line or non-alphabetic suffix character found>
    • /
    • g - подставь во всем мире. Но, поскольку регулярное выражение никогда не возвращается, оно будет заменять 2 слова одновременно.
  • tl-перейти к метке l, если последняя s, они должным образом заменены одним true true true.

Без trueи \(^\|[^[:alpha:]]\), без них, например\($\|[^[:alpha:]]\)была бы заменена true rue, потому что суффикс trueсоответствовал бы.

Ниже приведены мои другие решения, которые также удаляют повторяющиеся слова через строки.

Мое первое решение было с rue rue. Поэтому сначала я буду превратить вход в парах с форматом uniq. Затем запустите его через <non-alphabetical sequence separating words encoded in hex> <a word>с игнорированием первого поля, а затем преобразуйте обратно. Это будет очень медленно:

uniq -f1

Но потом я заметил,что # recreate input cat <<EOF | true true, rohith Rohith; cold burn, and fact and fact good good? EOF # insert zero byte after each word and non-word # the -z option is from GNU sed sed -r -z 's/[[:alpha:]]+/\x00&\x00/g' | # for each pair (non-word, word) xargs -0 -n2 sh -c ' # ouptut hexadecimal representation of non-word printf "%s" "$1" | xxd -p | tr -d "\n" # and output space with the word printf " %s\n" "$2" ' -- | # uniq ignores empty fields - so make sure field1 always has something sed 's/^/-/' | # uniq while ignoring first field uniq -f1 | # for each pair (non-word in hex, word) xargs -n2 bash -c ' # just `printf "%s" "$1" | sed 's/^-//' | xxd -r -p` for posix shell # change non-word from hex to characters printf "%s" "${1:1}" | xxd -r -p # output word printf "%s" "$2" ' -- хорошо справляется с маркировкой входных данных - он помещает нулевые байты между каждым словом и не-словом. Так что я мог легко читать поток. Я могу игнорировать повторяющиеся слова в awk, читая поток с нулевым разделением в GNU awk и сравнивая последнее прочитанное слово:

sed

Вместо нулевого байта в качестве разделителя записей может использоваться что-то уникальное, например cat <<EOF | true true, rohith Rohith; cold burn, and fact and fact good good? EOF sed -r -z 's/[[:alpha:]]+/\x00&\x00/g' | gawk -vRS='\0' ' NR%2==1{ nonword=$0 } NR%2==0{ if (length(lastword) && lastword != $0) { printf "%s%s", lastword, nonword } lastword=$0 } END{ printf "%s%s", lastword, nonword }'

Проверено на repl . Выходные данные фрагментов:

^
https://stackoverflow.com/questions/59845282/remove-consecutive-duplicate-words-from-a-file-using-awk-or-sed/59846273#comment105827216_59846273
Не могли бы вы подробно описать выражение sed, которое вы пишете прямо в начале вашего ответа?
https://stackoverflow.com/questions/59845282/remove-consecutive-duplicate-words-from-a-file-using-awk-or-sed/59846273#comment105827256_59846273
RS='^'означает, что запись разбивается на каждый ^не может появиться во входных данных, вам было бы лучше использовать какой-то управляющий символ, так как это, вероятно, менее вероятно.. Никогда не используйте переменную с именем ^btw, поскольку она слишком похожа на число lи поэтому запутывает ваш код.
https://stackoverflow.com/questions/59845282/remove-consecutive-duplicate-words-from-a-file-using-awk-or-sed/59846273#comment105827752_59846273
@rvbarreto есть целое объяснение в пунктах ниже, я попытался объяснить его. Может быть, есть что-то, что я мог бы попытаться объяснить лучше?
https://stackoverflow.com/questions/59845282/remove-consecutive-duplicate-words-from-a-file-using-awk-or-sed/59846273#comment105833713_59846273
@KamilCuk это было прекрасно!
rvbarreto

21.01.2020 08:31:14

sed -E 's/(\w+) *\1/\1/g' sample.txt

образец.формат txt

“true true, rohith Rohith;
cold burn, and fact and fact good good?”

выход:

:~$ sed -E 's/(\w+) *\1/\1/g' sample.txt
“true, rohith Rohith;
cold burn, and fact and fact good?”

Объяснение

(\w) *\1- сопоставляет слово, разделенное пробелом того же слова, и сохраняет его

Walter A

21.01.2020 11:05:54

Простой sed:

echo "true true, rohith Rohith;
cold burn, and fact and fact good good?" | sed -r 's/(\w+) (\1)/\1/g'
Закрыть X