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


19

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

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

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

Ответы:


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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.