web-dev-qa-db-ja.com

ファイル内のさまざまな文字の数を数えるにはどうすればよいですか?

ファイル内のさまざまな文字の数を出力するプログラムが必要です。例:

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

これを行うツールが存在しますか?

19
Mnementh

以下はうまくいくはずです:

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

まず、各文字の後に改行を挿入し、各文字を独自の行に配置します。次に、並べ替えます。次に、uniqコマンドを使用して重複を削除し、各行の前にその文字の出現回数を付けます。

リストを頻度でソートするには、これをすべてsort -nrにパイプします。

20
Steven D

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) }'

Rubyを使用した、低速ですが比較的メモリフレンドリーなバージョンです。入力サイズに関係なく、約12 MBのRAM。

# 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
Jared Beck