端末でファイル内の単語の文字数を数える簡単な方法はありますか?

端末でファイル内の単語の文字数を数える簡単な方法はありますか?

私のファイルには1億行があります。

1行につき1列しかありません。

例えば

aaaaa
bb
cc
ddddddd
ee

文字数を一覧表示したいです。

このように

2 character words - 3
5 character words - 1
7 character words - 1

など。

端末で簡単にできる方法はありますか?

答え1

$ awk '{ print length }' file | sort -n | uniq -c | awk '{ printf("%d character words: %d\n", $2, $1) }'
2 character words: 3
5 character words: 1
7 character words: 1

最初のawkフィルタは、名前付きファイルの各行の長さのみを印刷しますfile。ファイルには1行に1語が含まれているとします。

sort -n出力の行を昇順に並べ替える)と(各行の連続発生回数を計算)は、指定したデータに対して次の出力を生成します。awkuniq -c

   3 2
   1 5
   1 7

awk次に、各行を「Y文字のX行」として解釈し、目的の出力を生成する2番目のスクリプトによって解析されます。


awk別の解決策は、すべての操作を配列として実行し、長さの数を保存することです。効率性、読みやすさ/理解しやすさ(およびメンテナンスの容易さ)のバランスをとることで、どのソリューションが「最高」なのかです。

代替ソリューション:

$ awk '{ len[length]++ } END { for (i in len) printf("%d character words: %d\n", i, len[i]) }' file
2 character words: 3
5 character words: 1
7 character words: 1

答え2

awk一人でやるもう一つの方法

$ awk '{words[length()]++} END{for(k in words)print k " character words - " words[k]}' ip.txt 
2 character words - 3
5 character words - 1
7 character words - 1
  • words[length()]++入力ラインの長さをキーにしてカウントを保存
  • END{for(k in words)print k " character words - " words[k]}すべての行が処理されたら、目的の形式で配列の内容を印刷します。


パフォーマンス比較、選択した数字が2つの実行の中で最高

$ wc words.txt
 71813  71813 655873 words.txt
$ perl -0777 -ne 'print $_ x 1000' words.txt > long_file.txt
$ du -h --apparent-size long_file.txt
626M    long_file.txt

$ time awk '{words[length()]++} END{for(k in words)print k " character words - " words[k]}' long_file.txt > t1

real    0m20.632s
user    0m20.464s
sys     0m0.108s

$ time perl -lne '$h{length($_)}++ }{ for $n (sort keys %h) {print "$n character words - $h{$n}"}' long_file.txt > t2

real    0m19.749s
user    0m19.640s
sys     0m0.108s

$ time awk '{ print length }' long_file.txt | sort -n | uniq -c | awk '{ printf("%d character words - %d\n", $2, $1) }' > t3

real    1m23.294s
user    1m24.952s
sys     0m1.980s

$ diff -s <(sort t1) <(sort t2)
Files /dev/fd/63 and /dev/fd/62 are identical
$ diff -s <(sort t1) <(sort t3)
Files /dev/fd/63 and /dev/fd/62 are identical

ファイルにASCII文字のみがある場合

$ time LC_ALL=C awk '{words[length()]++} END{for(k in words)print k " character words - " words[k]}' long_file.txt > t1

real    0m15.651s
user    0m15.496s
sys     0m0.120s

時間がperlあまり変わらない理由はよくわかりません。エンコードを別の方法で設定する必要があるかもしれません。

答え3

これはperlそれに対応するものです(オプション - ソートを含む)。

$ perl -lne '
    $h{length($_)}++ }{ for $n (sort keys %h) {print "$n character words - $h{$n}"}
' file
2 character words - 3
5 character words - 1
7 character words - 1

答え4

デリゲート一つGNU awkを呼び出すには、次のようにします。印刷機能:

$ awk 'BEGIN { PROCINFO["sorted_in"] = "@ind_str_asc"}
       {c[length($0)]++}
       END{
           for(i in c){printf("%s character words - %s\n",i,c[i])}
          }' infile
2 character words - 3
5 character words - 1
7 character words - 1

コアアルゴリズムは配列の文字数だけを収集します。最後の部分は、printf形式で収集された数を印刷します。

素早く簡単で、awkを一度だけ呼び出すだけです。

正確に言えば、配列を維持するためにより多くのメモリが使用されます。ただし、ソートは呼び出されず(数値配列インデックスは常にPROCINFOを使用してソートを検索するように設定されています)、外部プロシージャは複数ではなく1
つだけです。awk

関連情報