Самое частое слово в тексте

В дистрибутивах на основе Debian, как и в Ubuntu, вы можете найти и загрузить исходный код, как показано ниже:

$ which man
/usr/bin/man
$ dpkg --search /usr/bin/man
man-db: /usr/bin/man
$ apt-get source man-db

Это поместит исходный код в ваш текущий рабочий каталог.

1
11.06.2020, 17:16
2 ответа

Если список слов находится в файле с именем words, с одним словом в каждой строке (, возможно, созданным с помощью tr ' ' '\n' <originalwords >wordsдля разделения исходного списка на несколько строк ), тогда цикл

while IFS= read -r word; do
    grep -F -o -e "$word" words
done <words | awk '{ c[$0]++; if (c[$0] > c[w]) w = $0 } END { print w }'

выведет слово, которое чаще всего встречается в составе слов в списке (или, если много слов встречается одинаковое количество раз, одно из тех слов, которые встречаются первыми в списке ).

Он делает это, используя сам список как набор шаблонов для сопоставления со списком. С помощью -oмы просим возвращать совпадающие подстроки в отдельных строках.

Только вывод цикла,со списком, приведенным в вопросе, будет

play
ball
ball
ball
ball
football
basketball
snowball

Тогда остается просто подсчитать эти слова и выбрать то, которое встречается чаще всего.


Как полный скрипт, с обработкой временных файлов:

#!/bin/sh

tmpfile=$(mktemp)

trap 'rm -f "$tmpfile"' EXIT      # delete temporary file upon exiting

tr -s ' ' '\n' <"${1:-/dev/stdin}" >"$tmpfile"  # convert into word list

while IFS= read -r word; do
    grep -F -o -e "$word" "$tmpfile"
done <"$tmpfile" | awk '{ c[$0]++; if (c[$0] > c[w]) w = $0 } END { print w }'

Скрипт дополнительно читает из стандартного ввода, если файл не указан.

1
19.03.2021, 02:29
awk '{
        for (i=1; i<=NF; i++) {
                uwords[$i] = 0
                allwords[++idx] = $i
        }
     }
    END {
                if (idx == 0) exit
                max = 0
                for (w in uwords) {
                        count = 0
                        for (i=1; i<=idx; i++) {
                                if (allwords[i] ~ w) count++;
                        }
                        if (count > max) {
                                max = count
                                maxw = w
                        }
                }
                print maxw
        }'

Просканируйте ввод и извлеките список уникальных слов и список всех слов. (Думаю, нам не нужен список уникальных слов, но это может сделать вещи более эффективными в случае большого ввода. )Затем для каждого уникального слова подсчитайте, сколько слов в файле соответствует ему. (Итак, если файл содержит football football football, это означает 3 в направлении ball. )Следите за тем, у кого больше всего совпадений.

В случае ничьей он сообщает о слове, которое появляется первым в массивеuwords(уникальных слов ). Это не обязательно первое, что появляется в файле, и не первый в алфавитном порядке.

Это может привести к неожиданным результатам. если какое-либо из слов содержит ., *или [.


Если вы предпочитаете подход Кусалананды shell+awk, но не хотите ошибки пограничного случая, сделайте это:

tmpfile=$(mktemp)

trap 'rm -f "$tmpfile"' EXIT      # delete temporary file upon exiting

tr -s ' ' '\n' < "${1:-/dev/stdin}" > "$tmpfile"  # convert into word list

sort -u "$tmpfile" | while IFS= read -r word
do
    grep -F -o -e "$word" "$tmpfile"
done | awk '{ c[$0]++; if (c[$0] > c[w]) w = $0 } END { print w }'

Сортируя список слов, мы получаем список уникальных слов, и, таким образом, не считать слова несколько раз.

Обратите внимание, что этот код явно предполагает что существует не более одного входного файла (но файла могло и не быть; т. е. читать со стандартного ввода ). Это соответствует формулировке вопроса. Однако,если может быть любое количество входных файлов (ноль, один, или более ), измените строку trна

cat -- "$@" | tr -s ' ' '\n' > "$tmpfile"         # convert into word list

Возможно, это UUOC, но

  • он обрабатывает два или более входных файла и
  • более читабелен, чем < "${1:-/dev/stdin}".
1
19.03.2021, 02:29

Теги

Похожие вопросы