Come posso contare il numero di caratteri diversi in un file?


19

Avrei bisogno di un programma che produca il numero dei diversi personaggi in un file. Esempio:

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

Esiste uno strumento che lo fa?

Risposte:


21

Il seguente dovrebbe funzionare:

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

Innanzitutto, inseriamo una nuova riga dopo ogni personaggio, posizionando ciascun personaggio sulla propria riga. Quindi lo ordiniamo. Quindi usiamo il comando uniq per rimuovere i duplicati, prefissando ogni riga con il numero di occorrenze di quel carattere.

Per ordinare l'elenco per frequenza, reindirizza tutto sort -nr.


4
Su sed per Mac OS X èsed 's/\(.\)/\1\'$'\n/g' text.txt
mb21

Molto bello, ma sfortunatamente non funziona correttamente se il testo contiene caratteri Unicode (utf8). Potrebbe esserci un modo per sedfarlo, ma la soluzione Python di Jacob Vlijm ha funzionato bene per me.
Bitinerante il

14

La soluzione di Steven è buona, semplice. Non è così performante per file molto grandi (file che non si adattano comodamente a circa la metà della RAM) a causa del passaggio di ordinamento. Ecco una versione awk. E 'anche un po' più complicato, perché cerca di fare la cosa giusta per un paio di caratteri speciali (a capo, ', \, :).

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

Ecco una soluzione Perl sullo stesso principio. Perl ha il vantaggio di poter ordinare internamente. Inoltre, questo non conterà correttamente una nuova riga se il file non termina con un carattere di nuova riga.

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

1
+1 per non fare quel tipo orribile
Sparr

1

Una versione lenta ma relativamente favorevole alla memoria, usando ruby. Circa una dozzina di MB di RAM, indipendentemente dalle dimensioni dell'input.

# 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.