Answers:
以下应该工作:
$ sed 's/\(.\)/\1\n/g' text.txt | sort | uniq -c
首先,我们在每个字符后插入一个换行符,将每个字符放在自己的行上。然后我们对其进行排序。然后,我们使用uniq命令删除重复项,并在每行前添加该字符的出现次数。
要按频率对列表进行排序,请将其全部输入sort -nr
。
sed
做到这一点,但是Jacob Vlijm的Python解决方案对我来说效果很好。
史蒂文的解决方案是一个很好的简单解决方案。由于排序步骤,对于非常大的文件(大约一半的RAM无法容纳这些文件),它的性能不太好。这是awk版本。这也是一个有点复杂,因为它试图做正确的事的几个特殊字符(换行符'
,\
,:
)。
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/:/'
这是基于相同原理的Perl解决方案。Perl的优点是能够在内部排序。此外,如果文件未以换行符结尾,这将正确地不计入额外的换行符。
perl -ne '
++$c{$_} foreach split //;
END { printf "'\''%s'\'': %d\n", /[\\'\'']/ ? "\\$_" : /./ ? $_ : "\\n", $c{$_}
foreach (sort {$c{$b} <=> $c{$a}} keys %c) }'
使用ruby的缓慢但相对友好的版本。不管输入大小如何,大约有十几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
sed 's/\(.\)/\1\'$'\n/g' text.txt