Wie kann ich die Anzahl der verschiedenen Zeichen in einer Datei zählen?

19

Ich bräuchte ein Programm, das die Anzahl der verschiedenen Zeichen in einer Datei ausgibt. Beispiel:

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

Gibt es ein Tool, das das macht?

Mnementh
quelle

Antworten:

21

Folgendes sollte funktionieren:

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

Zuerst fügen wir nach jedem Zeichen eine neue Zeile ein, wobei jedes Zeichen in eine eigene Zeile gesetzt wird. Dann sortieren wir es. Dann verwenden wir den Befehl uniq, um die Duplikate zu entfernen, wobei jeder Zeile die Anzahl der Vorkommen dieses Zeichens vorangestellt wird.

Um die Liste nach Häufigkeit zu sortieren, leiten Sie dies alles in sort -nr.

Steven D
quelle
4
Auf Sed für Mac OS X ist essed 's/\(.\)/\1\'$'\n/g' text.txt
mb21
Sehr schön, aber leider funktioniert es nicht richtig, wenn der Text Unicode-Zeichen (utf8) enthält. Es mag einen Weg geben, dies zu sedtun, aber die Python-Lösung von Jacob Vlijm hat für mich gut funktioniert.
Bitinerant
14

Stevens Lösung ist gut und einfach. Bei sehr großen Dateien (Dateien, die nicht in die Hälfte des Arbeitsspeichers passen) ist die Leistung aufgrund des Sortierschritts nicht so hoch. Hier ist eine awk-Version. Es ist auch ein wenig komplizierter , weil es versucht , das Richtige für ein paar Sonderzeichen (Zeilenumbrüche, zu tun ', \, :).

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

Hier ist eine Perl-Lösung nach dem gleichen Prinzip. Perl hat den Vorteil, intern sortieren zu können. Dies wird auch eine zusätzliche Newline nicht korrekt zählen, wenn die Datei nicht mit einem Newline-Zeichen endet.

perl -ne '
  ++$c{$_} foreach split //;
  END { printf "'\''%s'\'': %d\n", /[\\'\'']/ ? "\\$_" : /./ ? $_ : "\\n", $c{$_}
        foreach (sort {$c{$b} <=> $c{$a}} keys %c) }'
Gilles 'SO - hör auf böse zu sein'
quelle
1
+1 für diese schreckliche Art nicht zu tun
Sparr
1

Eine langsame, aber relativ speicherfreundliche Version mit Ruby. Ungefähr ein Dutzend MB RAM, unabhängig von der Eingabegröße.

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