Ví dụ tôi có tệp 1.txt
, có chứa:
Moscow
Astana
Tokyo
Ottawa
Tôi muốn đếm số lượng của tất cả các char là:
a - 4,
b - 0,
c - 1,
...
z - 0
Ví dụ tôi có tệp 1.txt
, có chứa:
Moscow
Astana
Tokyo
Ottawa
Tôi muốn đếm số lượng của tất cả các char là:
a - 4,
b - 0,
c - 1,
...
z - 0
Câu trả lời:
Bạn có thể sử dụng điều này:
sed 's/\(.\)/\1\n/g' 1.txt | sort | uniq -ic
4
5 a
1 c
1 k
1 M
1 n
5 o
2 s
4 t
2 w
1 y
Phần sed
đặt một dòng mới sau mỗi nhân vật. Sau đó, chúng tôi sort
ouput theo thứ tự abc. Và cuối cùng uniq
đếm số lần xuất hiện. Các -i
lá cờ của uniq
thể Bỏ qua phần nếu bạn không muốn trường hợp vô hồn.
sort -k 2
danh sách chữ và số.
sed -e $'s/\(.\)/\\1\\\n/g'
(xem thêm stackoverflow.com/a/18410122/179014 )
| sort -rnk 1
. Và nếu bạn đang xử lý các tệp rất lớn, như tôi, bạn có thể lấy mẫu vài nghìn dòng để lấy proxy cho số lượng thực tế:cat 1.txt | shuf -n 10000 | sed 's/\(.\)/\1\n/g' | sort | uniq -ic | sort -rnk 1
Hơi muộn một chút, nhưng để hoàn thành bộ, một cách tiếp cận python (3) khác, đã sắp xếp kết quả:
#!/usr/bin/env python3
import sys
chars = open(sys.argv[1]).read().strip().replace("\n", "")
[print(c+" -", chars.count(c)) for c in sorted(set([c for c in chars]))]
A - 1
M - 1
O - 1
T - 1
a - 4
c - 1
k - 1
n - 1
o - 4
s - 2
t - 3
w - 2
y - 1
Đọc tệp, bỏ qua khoảng trắng và trả về dưới dạng "ký tự":
chars = open(sys.argv[1]).read().strip().replace("\n", "")
Tạo một tập hợp (sắp xếp) các đơn vị:
sorted(set([c for c in chars]))
Đếm và in sự xuất hiện của từng ký tự:
print(c+" -", chars.count(c)) for c in <uniques>
chars_count.py
Chạy nó với tệp dưới dạng đối số:
/path/to/chars_count.py </path/to/file>
nếu tập lệnh có thể thực thi được, hoặc:
python3 /path/to/chars_count.py </path/to/file>
nếu nó không phải là
Theo mặc định trong awk , eparator F ield S (FS) là khoảng trắng hoặc tab . Vì chúng tôi muốn đếm từng ký tự, chúng tôi sẽ phải xác định lại FS thành không có gì ( FS=""
) để tách từng ký tự thành một dòng riêng biệt và lưu nó thành một mảng và ở cuối END{..}
khối bên trong , in tổng số lần xuất hiện của chúng bằng lệnh awk sau :
$ awk '{for (i=1;i<=NF;i++) a[$i]++} END{for (c in a) print c,a[c]}' FS="" file
A 1
M 1
O 1
T 1
a 4
c 1
k 1
n 1
o 4
s 2
t 3
w 2
y 1
Trong {for (i=1;i<=NF;i++) a[$i]++} ... FS="" ...
khối chúng tôi chỉ chia các ký tự. Và
trong END{for (c in a) print c,a[c]}
khối, chúng tôi đang lặp lại mảng a
và in ký tự đã lưu trong đó print c
và số lần xuất hiện của nóa[c]
Thực hiện một for
vòng lặp cho tất cả các ký tự bạn muốn đếm và sử dụng grep -io
để có được tất cả các lần xuất hiện của ký tự và trường hợp bỏ qua, và wc -l
để đếm các trường hợp và in kết quả.
Như thế này:
#!/bin/bash
filename="1.txt"
for char in {a..z}
do
echo "${char} - `grep -io "${char}" ${filename} | wc -l`,"
done
Kịch bản đầu ra này:
a - 5,
b - 0,
c - 1,
d - 0,
e - 0,
f - 0,
g - 0,
h - 0,
i - 0,
j - 0,
k - 1,
l - 0,
m - 1,
n - 1,
o - 5,
p - 0,
q - 0,
r - 0,
s - 2,
t - 4,
u - 0,
v - 0,
w - 2,
x - 0,
y - 1,
z - 0,
EDIT sau khi bình luận
Để tạo một vòng lặp cho tất cả các ký tự có thể in, bạn có thể làm điều này:
#!/bin/bash
filename="a.txt"
for num in {32..126}
do
char=`printf "\x$(printf %x ${num})"`
echo "${char} - `grep -Fo "${char}" ${filename} | wc -l`,"
done
Điều này sẽ đếm tất cả các ký tự ANSI từ 32 đến 126 - đây là những ký tự phổ biến nhất có thể đọc được. Lưu ý rằng điều này không sử dụng trường hợp bỏ qua.
đầu ra từ đây sẽ là:
- 0,
! - 0,
" - 0,
# - 0,
$ - 0,
% - 0,
& - 0,
' - 0,
( - 0,
) - 0,
* - 0,
+ - 0,
, - 0,
- - 0,
. - 0,
/ - 0,
0 - 0,
1 - 0,
2 - 0,
3 - 0,
4 - 0,
5 - 0,
6 - 0,
7 - 0,
8 - 0,
9 - 0,
: - 0,
; - 0,
< - 0,
= - 0,
> - 0,
? - 0,
@ - 0,
A - 1,
B - 0,
C - 0,
D - 0,
E - 0,
F - 0,
G - 0,
H - 0,
I - 0,
J - 0,
K - 0,
L - 0,
M - 1,
N - 0,
O - 1,
P - 0,
Q - 0,
R - 0,
S - 0,
T - 1,
U - 0,
V - 0,
W - 0,
X - 0,
Y - 0,
Z - 0,
[ - 0,
\ - 0,
] - 0,
^ - 0,
_ - 0,
` - 0,
a - 4,
b - 0,
c - 1,
d - 0,
e - 0,
f - 0,
g - 0,
h - 0,
i - 0,
j - 0,
k - 1,
l - 0,
m - 0,
n - 1,
o - 4,
p - 0,
q - 0,
r - 0,
s - 2,
t - 3,
u - 0,
v - 0,
w - 2,
x - 0,
y - 1,
z - 0,
{ - 0,
| - 0,
} - 0,
~ - 0,
i
khỏi grep. (trong câu hỏi của bạn, bạn chỉ có 3 trong kết quả mong đợi)
grep
toàn bộ đầu vào liên tục.
Đây là một giải pháp khác (trong awk) ...
awk '
{ for (indx=length($0); indx >= 1; --indx)
++chars[tolower(substr($0, indx, 1))]
}
END { for (c in chars) print c, chars[c]; }
' 1.txt | sort
cat file | awk '...'
: bạn có thể trực tiếp nói awk '...' file
.
Các perl
oneliner sau đây sẽ làm số đếm. Tôi đặt regex trong ngữ cảnh danh sách (để lấy số lượng các trận đấu) và đặt nó vào bối cảnh vô hướng:
$ perl -e '$a=join("",<>);for("a".."z"){$d=()=$a=~/$_/gi;print"$_ - $d,\n"}' 1.txt
a - 5,
b - 0,
c - 1,
d - 0,
e - 0,
f - 0,
g - 0,
h - 0,
i - 0,
j - 0,
k - 1,
l - 0,
m - 1,
n - 1,
o - 5,
p - 0,
q - 0,
r - 0,
s - 2,
t - 4,
u - 0,
v - 0,
w - 2,
x - 0,
y - 1,
z - 0,
perl -Mfeature=say -e '$a=join("",<>);say join(",\n", map { sprintf("%s - %d", $_, ($d=()=$a=~/$_/gi)); } ("a".."z"))'
Đây là một giải pháp sử dụng Python:
#!/usr/bin/env python2
import collections, string
with open('1.txt') as f:
input_string = f.read().replace('\n', '').lower()
count_dict = collections.Counter(input_string)
for char in string.lowercase:
print char + ' - ' + str(count_dict[char]) + ','
Ở đây, chúng tôi đã sử dụng lớp collections
của mô-đun Counter
để đếm số lần xuất hiện của mỗi ký tự, sau đó để in, chúng tôi đã sử dụng string
mô-đun để lấy tất cả các chữ cái viết thường theo biến string.lowercase
.
Lưu tập lệnh trên trong một tệp đặt cho nó bất kỳ tên nào bạn muốn, vd count.py
. Bây giờ từ cùng một thư mục lưu tệp, bạn có thể chỉ cần chạy python count.py
để thực thi tệp, từ bất kỳ thư mục nào khác sử dụng đường dẫn tuyệt đối đến tệp để thực thi nghĩa là python /absolute/path/to/count.py
.
Cách đây một thời gian, tôi đã viết một chương trình C để làm điều đó, bởi vì tôi cần nó để xem các tệp lớn và tạo ra một số thống kê.
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>
#include <sysexits.h>
inline static double square(double x)
{
return x * x;
}
int main()
{
static const unsigned distribution_size = 1 << CHAR_BIT;
int rv = EX_OK;
uintmax_t *distribution = calloc(distribution_size, sizeof(*distribution));
{
int c;
while ((c = getchar()) != EOF)
distribution[c]++;
if (ferror(stdin)) {
perror("I/O error on standard input");
rv = EX_IOERR;
}
}
uintmax_t sum = 0;
for (unsigned i = 0; i != distribution_size; i++)
sum += distribution[i];
double avg = (double) sum / distribution_size;
double var_accum = 0.0;
for (unsigned i = 0; i != distribution_size; i++)
{
const uintmax_t x = distribution[i];
printf("'%c' (%02X): %20ju", isprint((int) i) ? i : ' ', i, x);
if (x != 0) {
var_accum += square((double) x - avg);
printf(" (%+.2e %%)\n", ((double) x / avg - 1.0) * 100.0);
} else {
var_accum += square(avg);
putchar('\n');
}
}
double stdev = sqrt(var_accum / distribution_size);
double varcoeff = stdev / avg;
printf(
"total: %ju\n"
"average: %e\n"
"standard deviation: %e\n"
"variation coefficient: %e\n",
sum, avg, stdev, varcoeff);
free(distribution);
return rv;
}
biên dịch với (giả sử mã nguồn nằm trong character-distribution.c
):
cc -std=c99 -O2 -g0 -o character-distribution character-distribution.c
chạy với:
./character-distribution < 1.txt
Nếu bạn chưa có trình biên dịch C, hãy cài đặt GCC:
sudo apt-get install gcc build-essential
Giải pháp tương tự với @heemayl, với mã chặt chẽ hơn, hoạt động trên Python 2.7 và Python 3.
#!/usr/bin/python
import collections
import fileinput
import itertools
import string
count = collections.Counter(itertools.chain(*fileinput.input()))
print(',\n'.join('{} - {}'.format(c, count[c] + count[c.upper()])
for c in string.ascii_lowercase))
Các tuyên bố đầu tiên, count = collections.Counter(…)
làm tất cả các công việc thực sự.
fileinput.input()
đọc mọi dòng của đầu vào, có thể được dẫn qua stdin hoặc dưới dạng đối số dòng lệnh.*
làm cho nó xem xét một nhân vật tại một thời điểm chứ không phải là một dòng tại một thời điểm.count = Counter(…)
đếm số lần xuất hiện của từng ký tự một cách hiệu quả, trong một lần chạy và lưu kết quả vào count
biến.Dòng thứ hai chỉ in kết quả.
'{} - {}'.format(c, count[c] + count[c.upper()]) for c in string.ascii_lowercase
làm cho một danh sách của mỗi nhân vật và số lượng của nó.print(',\n'.join(…))
đặt nó ở định dạng mong muốn: một trên mỗi dòng, được phân tách bằng dấu phẩy, nhưng không có dấu phẩy trên dòng cuối cùng.GNU awk 4.1
awk -iwalkarray '{for (;NF;NF--) b[$NF]++} END {walk_array(b)}' FS=
[A] = 1
[O] = 1
[w] = 2
[k] = 1
[y] = 1
[T] = 1
[n] = 1
[a] = 4
[o] = 4
[c] = 1
[s] = 2
[t] = 3
[M] = 1
Nếu bạn có phiên bản GNU awk trước đó, bạn có thể sử dụng for (c in b) print c, b[c]
.
Dưới đây là câu trả lời bằng ruby. Nó được thực hiện bằng cách thay đổi chuỗi thành một danh sách uniq của các ký tự khác nhau và sử dụng phương thức đếm trên mỗi ký tự.
#!/usr/bin/env ruby
String content = IO.read("1.txt")
content.split("").uniq.sort.each { |chr| puts( chr + ' - ' + content.count(chr).to_s) }