Comment puis-je compter le nombre de caractères différents dans un fichier?


19

J'aurais besoin d'un programme qui génère le nombre de caractères différents dans un fichier. Exemple:

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

Existe un outil, qui fait ça?

Réponses:


21

Les éléments suivants devraient fonctionner:

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

Tout d'abord, nous insérons une nouvelle ligne après chaque caractère, en mettant chaque caractère sur sa propre ligne. Ensuite, nous le trions. Ensuite, nous utilisons la commande uniq pour supprimer les doublons, en préfixant chaque ligne avec le nombre d'occurrences de ce caractère.

Pour trier la liste par fréquence, canalisez tout cela dans sort -nr.


4
Sur sed pour Mac OS X c'estsed 's/\(.\)/\1\'$'\n/g' text.txt
mb21

Très bien, mais malheureusement cela ne fonctionne pas correctement si le texte contient des caractères Unicode (utf8). Il y a peut-être un moyen de le faire sed, mais la solution Python de Jacob Vlijm a bien fonctionné pour moi.
bitinerant

14

La solution de Steven est bonne et simple. Ce n'est pas si performant pour les très gros fichiers (les fichiers qui ne tiennent pas confortablement dans environ la moitié de votre RAM) en raison de l'étape de tri. Voici une version awk. Il est aussi un peu plus compliqué , car il essaie de faire la bonne chose pour quelques caractères spéciaux (sauts de ligne, ', \, :).

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

Voici une solution Perl sur le même principe. Perl a l'avantage de pouvoir trier en interne. De plus, cela ne comptera pas correctement une nouvelle ligne supplémentaire si le fichier ne se termine pas par un caractère de nouvelle ligne.

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

1
+1 pour ne pas avoir fait ce genre de chose horrible
Sparr

1

Une version lente mais relativement conviviale, utilisant du rubis. Environ une douzaine de Mo de RAM, quelle que soit la taille d'entré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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.