Ответы:
Следующее должно работать:
$ sed 's/\(.\)/\1\n/g' text.txt | sort | uniq -c
Сначала мы вставляем новую строку после каждого символа, помещая каждый символ в отдельную строку. Тогда мы сортируем это. Затем мы используем команду uniq, чтобы удалить дубликаты, добавляя к каждой строке префикс числа вхождений этого символа.
Чтобы отсортировать список по частоте, направьте все это в sort -nr
.
sed
это, но решение Python от Jacob Vlijm хорошо сработало для меня.
Решение Стивена хорошее, простое. Это не так эффективно для очень больших файлов (файлы, которые не помещаются удобно примерно в половине вашей оперативной памяти) из-за шага сортировки. Вот версия awk. Это также немного более сложное , потому что он пытается сделать правильную вещь для нескольких специальных символов (символ новой строки, '
, \
, :
).
awk '
{for (i=1; i<=length; i++) ++c[substr($0,i,1)]; ++c[RS]}
function chr (x) {return x=="\n" ? "\\n" : x==":" ? "\\072" :
x=="\\" || x=="'\''" ? "\\" x : x}
END {for (x in c) printf "'\''%s'\'': %d\n", chr(x), c[x]}
' | sort -t : -k 2 -r | sed 's/\\072/:/'
Вот решение Perl по тому же принципу. Преимущество Perl заключается в возможности внутренней сортировки. Также это не будет правильно считать лишнюю новую строку, если файл не заканчивается символом новой строки.
perl -ne '
++$c{$_} foreach split //;
END { printf "'\''%s'\'': %d\n", /[\\'\'']/ ? "\\$_" : /./ ? $_ : "\\n", $c{$_}
foreach (sort {$c{$b} <=> $c{$a}} keys %c) }'
Медленная, но относительно дружественная к памяти версия, использующая ruby. Около десятка МБ ОЗУ, независимо от размера ввода.
# count.rb
ARGF.
each_char.
each_with_object({}) {|e,a| a[e] ||= 0; a[e] += 1}.
each {|i| puts i.join("\t")}
ruby count.rb < input.txt
t 20721
d 20628
S 20844
k 20930
h 20783
... etc
sed 's/\(.\)/\1\'$'\n/g' text.txt