Как я могу посчитать количество разных символов в файле?

19

Мне нужна программа, которая выводит количество различных символов в файле. Пример:

> stats testfile
' ': 207
'e': 186
'n': 102

Существует какой-нибудь инструмент, который это делает?

Mnementh
источник

Ответы:

21

Следующее должно работать:

$ sed 's/\(.\)/\1\n/g' text.txt | sort | uniq -c

Сначала мы вставляем новую строку после каждого символа, помещая каждый символ в отдельную строку. Тогда мы сортируем это. Затем мы используем команду uniq, чтобы удалить дубликаты, добавляя к каждой строке префикс числа вхождений этого символа.

Чтобы отсортировать список по частоте, направьте все это в sort -nr.

Стивен Д
источник
4
На sed для Mac OS X этоsed 's/\(.\)/\1\'$'\n/g' text.txt
mb21
Очень хорошо, но, к сожалению, он не работает правильно, если текст содержит символы Unicode (utf8). Может быть, есть способ сделать sedэто, но решение Python от Jacob Vlijm хорошо сработало для меня.
битинер
14

Решение Стивена хорошее, простое. Это не так эффективно для очень больших файлов (файлы, которые не помещаются удобно примерно в половине вашей оперативной памяти) из-за шага сортировки. Вот версия 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) }'
Жиль "ТАК - прекрати быть злым"
источник
1
+1 за то, что не сделал этого ужасного вида
Спарр
1

Медленная, но относительно дружественная к памяти версия, использующая 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
Джаред Бек
источник