Câu trả lời:
Sau đây nên làm việc:
$ sed 's/\(.\)/\1\n/g' text.txt | sort | uniq -c
Đầu tiên, chúng tôi chèn một dòng mới sau mỗi ký tự, đặt mỗi ký tự trên dòng riêng. Sau đó, chúng tôi sắp xếp nó. Sau đó, chúng tôi sử dụng lệnh uniq để loại bỏ các bản sao, tiền tố mỗi dòng với số lần xuất hiện của ký tự đó.
Để sắp xếp danh sách theo tần suất, hãy đưa tất cả vào sort -nr
.
sed
điều này, nhưng giải pháp Python của Jacob Vlijm hoạt động tốt với tôi.
Giải pháp của Steven là một giải pháp tốt, đơn giản. Nó không hiệu quả đối với các tệp rất lớn (các tệp không vừa vặn trong khoảng một nửa RAM của bạn) do bước sắp xếp. Đây là một phiên bản awk. Nó cũng là một chút phức tạp hơn vì nó cố gắng làm điều đúng cho một vài ký tự đặc biệt (dòng mới, '
, \
, :
).
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/:/'
Đây là một giải pháp Perl trên cùng một nguyên tắc. Perl có lợi thế là có thể sắp xếp nội bộ. Ngoài ra, điều này sẽ không chính xác không tính thêm một dòng mới nếu tệp không kết thúc bằng một ký tự dòng mới.
perl -ne '
++$c{$_} foreach split //;
END { printf "'\''%s'\'': %d\n", /[\\'\'']/ ? "\\$_" : /./ ? $_ : "\\n", $c{$_}
foreach (sort {$c{$b} <=> $c{$a}} keys %c) }'
Một phiên bản chậm nhưng tương đối thân thiện với bộ nhớ, sử dụng ruby. Khoảng một chục MB RAM, bất kể kích thước đầu vào.
# 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