如何计算文件中不同字符的数量?

如何计算文件中不同字符的数量?

我需要一个程序,输出文件中不同字符的数量。例子:

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

存在任何工具可以做到这一点吗?

答案1

以下应该有效:

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

首先,我们在每个字符后面插入一个换行符,将每个字符放在自己的行上。然后我们对其进行排序。然后我们使用 uniq 命令删除重复项,并在每行前面加上该字符出现的次数。

要按频率对列表进行排序,请将所有内容通过管道传输到sort -nr.

答案2

史蒂文的解决方案是一个很好、简单的解决方案。由于排序步骤,对于非常大的文件(无法轻松容纳大约一半 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) }'

答案3

一个缓慢但相对内存友好的版本,使用 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

答案4

简单且性能相对较高:

fold -c1 testfile.txt | sort | uniq -c

只需告诉fold每 1 个字符后换行(即插入换行符)即可。



如何测试:

  • 128MB 全 ASCII 文件
    • find . -type f -name '*.[hc]' -exec cat {} >> /tmp/big.txt \;由一些代码库创建。
  • 工作站级机器(真铁,不是虚拟机)
  • 环境变量LC_ALL=C

运行时间按降序排列:

  • 史蒂文的sed|sort|uniq解决方案(https://unix.stackexchange.com/a/5011/427210): 102.5 秒
  • 我的fold|sort|uniq解决方案:59.3秒
  • 我的fold|sort|uniq解决方案,--buffer-size=12G选项为sort:38.9秒
  • 我的fold|sort|uniq解决方案,给出的--buffer-size=12G选项--stablesort:37.9秒
  • 贾尔斯的perl解决方案(https://unix.stackexchange.com/a/5013/427210): 34.0 秒
    • 优胜者!就像他们说的,最快的排序是不必排序:-)

相关内容