Bir dosyadaki farklı karakterlerin sayısını nasıl sayabilirim?


19

Bir dosyadaki farklı karakterlerin sayısını veren bir programa ihtiyacım var. Misal:

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

Herhangi bir araç var, bunu yapan?

Yanıtlar:


21

Aşağıdakiler işe yaramalıdır:

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

İlk olarak, her karakterden sonra yeni bir satır ekleyerek her karakteri kendi satırına koyarız. Sonra sıralarız. Ardından, her satıra o karakterin yineleme sayısını ekleyerek yinelemeleri kaldırmak için uniq komutunu kullanırız.

Listeyi frekansa göre sıralamak için, bunların tümünü boruya ekleyin sort -nr.


4
Mac OS X için sed üzerindesed 's/\(.\)/\1\'$'\n/g' text.txt
mb21

Çok güzel, ancak metin Unicode (utf8) karakterleri içeriyorsa maalesef düzgün çalışmıyor. Bunu yapmanın bir yolu olabilir sed, ama Jacob Vlijm'in Python çözümü benim için iyi çalıştı.
bitinerant

14

Steven'ın çözümü iyi, basit bir çözümdür. Sıralama aşaması nedeniyle çok büyük dosyalar (RAM'inizin yarısına rahatça sığmayan dosyalar) için çok performanssızdır. İşte bir awk versiyonu. Bu bir kaç özel karakterler için doğru olanı yapmaya çalışır çünkü karmaşık da biraz daha yüksek (yeni satırlar, ', \, :).

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/:/'

İşte aynı prensipte bir Perl çözümü. Perl dahili olarak sıralama yapabilme avantajına sahiptir. Ayrıca, dosya yeni satır karakteri ile bitmezse, bu durum fazladan yeni bir satır saymaz.

perl -ne '
  ++$c{$_} foreach split //;
  END { printf "'\''%s'\'': %d\n", /[\\'\'']/ ? "\\$_" : /./ ? $_ : "\\n", $c{$_}
        foreach (sort {$c{$b} <=> $c{$a}} keys %c) }'

1
Korkunç sıralama yapmadıkları için +1
Sparr

1

Ruby kullanan yavaş ama nispeten bellek dostu bir sürüm. Giriş boyutundan bağımsız olarak yaklaşık bir düzine 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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.