我需要一个程序,输出文件中不同字符的数量。例子:
> 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
选项--stable
为sort
:37.9秒 - 贾尔斯的
perl
解决方案(https://unix.stackexchange.com/a/5013/427210): 34.0 秒- 优胜者!就像他们说的,最快的排序是不必排序。
:-)
- 优胜者!就像他们说的,最快的排序是不必排序。