ファイル内のさまざまな文字数を数える方法は?

ファイル内のさまざまな文字数を数える方法は?

ファイルの固有文字数を出力するプログラムが必要です。例:

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

これを行うツールはありますか?

答え1

次は動作します。

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

まず、各文字の後に改行文字を挿入して、各文字を独自の行に配置します。それからソートしてみましょう。次に uniq コマンドを使用して重複を削除し、各行の前にその文字の発生回数を追加します。

頻度でリストを並べ替えるには、すべての項目をsort -nr

答え2

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

答え3

Rubyを使用するのは遅いが比較的メモリに優しいバージョンです。入力サイズに関係なく、約12MBの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

答え4

シンプルで比較的パフォーマンスが良いです。

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

fold1文字ごとに改行(たとえば改行を挿入)するように指示します。



テスト方法:

  • 128MBフル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ソリューション:38.9秒--buffer-size=12Gsort
  • 私のfold|sort|uniq解決策、与えられたオプション--buffer-size=12G:37.9秒--stablesort
  • Gilesのperlソリューション(https://unix.stackexchange.com/a/5013/427210):34.0秒
    • 勝者!彼らが言ったように、最も速いソートは並べ替える必要はありません。:-)

関連情報