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

Необходимо использовать termcap(5) функция. В странице справочника на некоторых Нельдах говорится, что этот инструмент устаревший и использовать terminfo, но это все еще доступно на другихterminfo более сложно).

Что еще более важно, less использование termcap.


Выбирание цветов для less

Я делаю следующее так, чтобы less и man (который использует less) будет иметь цвет:

$ cat ~/.LESS_TERMCAP 
export LESS_TERMCAP_mb=$(tput bold; tput setaf 2) # green
export LESS_TERMCAP_md=$(tput bold; tput setaf 6) # cyan
export LESS_TERMCAP_me=$(tput sgr0)
export LESS_TERMCAP_so=$(tput bold; tput setaf 3; tput setab 4) # yellow on blue
export LESS_TERMCAP_se=$(tput rmso; tput sgr0)
export LESS_TERMCAP_us=$(tput smul; tput bold; tput setaf 7) # white
export LESS_TERMCAP_ue=$(tput rmul; tput sgr0)
export LESS_TERMCAP_mr=$(tput rev)
export LESS_TERMCAP_mh=$(tput dim)
export LESS_TERMCAP_ZN=$(tput ssubm)
export LESS_TERMCAP_ZV=$(tput rsubm)
export LESS_TERMCAP_ZO=$(tput ssupm)
export LESS_TERMCAP_ZW=$(tput rsupm)
export GROFF_NO_SGR=1         # For Konsole and Gnome-terminal

И затем в моем ~/.bashrc, Я делаю это:

# Get color support for 'less'
export LESS="--RAW-CONTROL-CHARS"

# Use colors for less, man, etc.
[[ -f ~/.LESS_TERMCAP ]] && . ~/.LESS_TERMCAP

Примечание: См. документацию относительно LESS_TERMCAP_* переменные? поскольку, как это работает.

Конечный результат

    ss of man page

19
19.12.2010, 19:35
5 ответов

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

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

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

Для сортировки списка по частоте передайте это все по каналу в sort -nr.

21
27.01.2020, 19:45
  • 1
    На sed для Mac OS X это sed 's/\(.\)/\1\'$'\n/g' text.txt –  mb21 20.12.2013, 11:08

Решением Steven является хорошее, простое. Это не таким образом производительно для очень больших файлов (файлы, которые не подходят удобно приблизительно к половине Вашей RAM) из-за шага сортировки. Вот 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) }'
14
27.01.2020, 19:45
  • 1
    +1 для того, чтобы не сделать тот ужасный вид –  Sparr 20.12.2010, 00:00

Медленная, но относительно -дружественная к памяти версия, использующая 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
1
27.01.2020, 19:45

Более очевидное решение, которое я использую для подсчета появления символов в файле:

cat filename | grep -o. | sort | uniq -c | sort -bnr

направляет вывод в grep, который затем печатает каждый символ в одной строке | sortзатем перепечатывает каждый символ столько раз, сколько раз он появляется в файле | uniqподсчитывает количество вхождений | sort -nснова сортирует этот ввод, по номеру

С файлом, содержащим текст «Арахисовое масло и желе заставили пожилую женщину задуматься о своем прошлом».

Выход:

     13  
      9 e
      7 d
      5 s
      5 a
      4 o
      4 h

... and more

В первой строке будет указано количество пробелов в файле, вы можете отфильтровать это, если хотите, используяtr -d " "

0
11.12.2020, 06:55

Простой и относительно производительный:

fold -c1 testfile.txt | sort | uniq -c

Просто скажите foldобернуть (, т.е. вставить новую строку )после каждого 1 символа.



Как проверяли:

  • 128 МБ, все -ASCII-файл
    • Создано find. -type f -name '*.[hc]' -exec cat {} >> /tmp/big.txt \;в нескольких кодовых базах.
  • рабочая станция -машина класса (настоящее железо, а не ВМ)
  • переменная окруженияLC_ALL=C

Время выполнения в порядке убывания:

  • Решение Стивена sed|sort|uniq(https://unix.stackexchange.com/a/5011/427210):102,5 с
  • мое fold|sort|uniqрешение :59,3 сек
  • мое fold|sort|uniqрешение с опцией --buffer-size=12Gдляsort:38,9 сек
  • мое решение fold|sort|uniq, с параметрами --buffer-size=12Gи --stable, заданными дляsort:37,9 сек
  • Решение Джайлза perl(https://unix.stackexchange.com/a/5013/427210):34,0 сек.
    • Победитель! Как говорится, самая быстрая сортировка не требует сортировки .:-)
1
24.12.2020, 03:52

Теги

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