Zum Beispiel habe ich eine Datei 1.txt
, die enthält:
Moscow
Astana
Tokyo
Ottawa
Ich möchte die Anzahl aller Zeichen zählen als:
a - 4,
b - 0,
c - 1,
...
z - 0
Zum Beispiel habe ich eine Datei 1.txt
, die enthält:
Moscow
Astana
Tokyo
Ottawa
Ich möchte die Anzahl aller Zeichen zählen als:
a - 4,
b - 0,
c - 1,
...
z - 0
Antworten:
Sie könnten dies verwenden:
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
Das sed
Teil fügt nach jedem Zeichen eine neue Zeile ein. Dann geben wir sort
die Ausgabe in alphabetischer Reihenfolge ein. Und schließlich uniq
zählt die Anzahl der Vorkommen. Die Markierung -i
von uniq
kann weggelassen werden, wenn Sie keine Unterscheidung zwischen Groß- und Kleinschreibung wünschen.
sort -k 2
eine alphanumerische Liste umzuleiten.
sed -e $'s/\(.\)/\\1\\\n/g'
(siehe auch stackoverflow.com/a/18410122/179014 )
| sort -rnk 1
. Und wenn Sie mit sehr großen Dateien arbeiten, wie ich es bin, können Sie einfach ein paar Tausend Zeilen cat 1.txt | shuf -n 10000 | sed 's/\(.\)/\1\n/g' | sort | uniq -ic | sort -rnk 1
Etwas spät, aber um das Set zu vervollständigen, ein anderer Python (3) -Ansatz, sortiertes Ergebnis:
#!/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
Lesen Sie die Datei, überspringen Sie Leerzeichen und geben Sie sie als "Zeichen" zurück:
chars = open(sys.argv[1]).read().strip().replace("\n", "")
Erstellen Sie eine (sortierte) Menge von Unikaten:
sorted(set([c for c in chars]))
Zähle und drucke das Vorkommen für jedes der Zeichen:
print(c+" -", chars.count(c)) for c in <uniques>
chars_count.py
Führen Sie es mit der Datei als Argument aus:
/path/to/chars_count.py </path/to/file>
wenn das Skript ausführbar ist, oder:
python3 /path/to/chars_count.py </path/to/file>
wenn nicht
Standardmäßig in awk die F ield S eparator (FS) ist Raum oder Tab . Da wir jedes Zeichen zählen möchten, müssen wir den FS in nothing ( FS=""
) umdefinieren , um jedes Zeichen in einer separaten Zeile zu teilen und in einem Array zu speichern. Am Ende des END{..}
Blocks geben wir dessen Gesamtvorkommen mit dem folgenden awk- Befehl aus:
$ 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
Im {for (i=1;i<=NF;i++) a[$i]++} ... FS="" ...
Block teilen wir nur die Zeichen. Und
im END{for (c in a) print c,a[c]}
Block werden die a
gespeicherten Zeichen print c
und ihre Häufigkeit in einer Schleife angeordnet und gedruckta[c]
Führen Sie eine for
Schleife für alle Zeichen durch, die Sie zählen möchten, und verwenden Sie diese grep -io
, um alle Vorkommen des Zeichens abzurufen und Groß- und Kleinschreibung zu ignorierenwc -l
Instanzen zu zählen und das Ergebnis auszudrucken.
So was:
#!/bin/bash
filename="1.txt"
for char in {a..z}
do
echo "${char} - `grep -io "${char}" ${filename} | wc -l`,"
done
Das Skript gibt Folgendes aus:
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,
BEARBEITEN nach Kommentar
So erstellen Sie eine Schleife für alle druckbaren Zeichen:
#!/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
Dies zählt alle ANSI-Zeichen von 32 bis 126 - die am häufigsten lesbaren. Beachten Sie, dass dies keine Groß- und Kleinschreibung verwendet.
Ausgabe davon wird sein:
- 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
aus dem grep. (In Ihrer Frage hatten Sie nur 3 im erwarteten Ergebnis)
grep
den gesamten Eingang wiederholt.
Hier eine andere Lösung (in 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 '...'
: Sie können direkt sagen awk '...' file
.
Der folgende perl
Oneliner wird die Zählung durchführen. Ich habe den regulären Ausdruck in den Listenkontext gestellt (um die Anzahl der Übereinstimmungen zu erhalten) und das in den skalaren Kontext gestellt:
$ 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"))'
Hier ist eine Lösung mit 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]) + ','
Hier haben wir collections
die Counter
Klasse des Moduls verwendet, um die Anzahl der Vorkommen jedes Zeichens zu zählen, und zum Drucken haben wir das string
Modul verwendet, um alle Kleinbuchstaben der Variablen abzurufen string.lowercase
.
Speichern Sie das obige Skript in einer Datei, und geben Sie ihm einen beliebigen Namen, z count.py
. Von demselben Verzeichnis aus, in dem die Datei gespeichert ist, können Sie sie einfach python count.py
ausführen. In jedem anderen Verzeichnis verwenden Sie den absoluten Pfad zur Datei, um sie auszuführen python /absolute/path/to/count.py
.
Vor einiger Zeit habe ich ein C-Programm dafür geschrieben, weil ich es brauchte, um große Dateien zu betrachten und Statik zu erzeugen.
#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;
}
kompiliere mit (vorausgesetzt der Quellcode befindet sich in character-distribution.c
):
cc -std=c99 -O2 -g0 -o character-distribution character-distribution.c
lauf mit:
./character-distribution < 1.txt
Wenn Sie keinen C-Compiler bereit haben, installieren Sie GCC:
sudo apt-get install gcc build-essential
Ähnliche Lösung zu @heemayl, mit engerem Code, der auf Python 2.7 und Python 3 funktioniert.
#!/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))
Die erste Aussage count = collections.Counter(…)
erledigt die ganze wirkliche Arbeit.
fileinput.input()
Liest jede Zeile der Eingabe, die über stdin oder als Befehlszeilenargumente weitergeleitet werden kann.*
Lässt es ein Zeichen auf einmal betrachten, anstatt eine Zeile auf einmal.count = Counter(…)
Zählt die Vorkommen jedes Zeichens effizient in einem Durchgang und speichert das Ergebnis in der count
Variablen.Die zweite Zeile gibt nur die Ergebnisse aus.
'{} - {}'.format(c, count[c] + count[c.upper()]) for c in string.ascii_lowercase
erstellt eine Liste aller Zeichen und ihrer Anzahl.print(',\n'.join(…))
Versetzt es in das gewünschte Format: eins pro Zeile, getrennt durch Kommas, aber kein Komma in der letzten Zeile.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
Wenn Sie eine frühere Version von GNU awk haben, können Sie diese verwenden for (c in b) print c, b[c]
.
Hier ist die Antwort mit Rubin. Dazu wird die Zeichenfolge in eine eindeutige Liste der verschiedenen Zeichen geändert und für jedes Zeichen die Zählmethode verwendet.
#!/usr/bin/env ruby
String content = IO.read("1.txt")
content.split("").uniq.sort.each { |chr| puts( chr + ' - ' + content.count(chr).to_s) }