Ad esempio ho un file 1.txt
che contiene:
Moscow
Astana
Tokyo
Ottawa
Voglio contare il numero di tutti i caratteri come:
a - 4,
b - 0,
c - 1,
...
z - 0
Ad esempio ho un file 1.txt
che contiene:
Moscow
Astana
Tokyo
Ottawa
Voglio contare il numero di tutti i caratteri come:
a - 4,
b - 0,
c - 1,
...
z - 0
Risposte:
Puoi usare questo:
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
La sed
parte inserisce una nuova riga dopo ogni personaggio. Poi abbiamo sort
l'uscita in ordine alfabetico. E infine uniq
conta il numero di occorrenze. La -i
bandiera di uniq
può essere attivata se non si desidera l'insensibilità al caso.
sort -k 2
per elencarli alfanumericamente.
sed -e $'s/\(.\)/\\1\\\n/g'
(vedi anche stackoverflow.com/a/18410122/179014 )
| sort -rnk 1
. E se hai a che fare con file molto grandi, come me, puoi semplicemente campionare alcune migliaia di righe per ottenere un proxy per i conteggi effettivi:cat 1.txt | shuf -n 10000 | sed 's/\(.\)/\1\n/g' | sort | uniq -ic | sort -rnk 1
Un po 'in ritardo, ma per completare il set, un altro approccio a Python (3), ha ordinato il risultato:
#!/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
Leggi il file, salta gli spazi e ritorna come "caratteri":
chars = open(sys.argv[1]).read().strip().replace("\n", "")
Crea un set (ordinato) di elementi unici:
sorted(set([c for c in chars]))
Contare e stampare l'occorrenza per ciascuno dei personaggi:
print(c+" -", chars.count(c)) for c in <uniques>
chars_count.py
Eseguilo con il file come argomento tramite:
/path/to/chars_count.py </path/to/file>
se lo script è eseguibile o:
python3 /path/to/chars_count.py </path/to/file>
se non lo è
Per default in awk la F ield S eparator (FS) è spazio o tab . Poiché vogliamo contare ogni carattere, dovremo ridefinire il valore FS in nulla ( FS=""
) per dividere ogni carattere in una riga separata e salvarlo in un array e alla fine all'interno del END{..}
blocco, stampare le loro occorrenze totali con il seguente comando awk :
$ 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
Nel {for (i=1;i<=NF;i++) a[$i]++} ... FS="" ...
blocco abbiamo appena diviso i personaggi. E
in END{for (c in a) print c,a[c]}
blocco stiamo eseguendo il looping per la matrice a
e stampando il carattere salvato in esso print c
e il suo numero di occorrenzea[c]
Fai un for
ciclo per tutti i personaggi che vuoi contare e usa grep -io
per ottenere tutte le occorrenze del personaggio e ignorare il caso, wc -l
contare le istanze e stampare il risultato.
Come questo:
#!/bin/bash
filename="1.txt"
for char in {a..z}
do
echo "${char} - `grep -io "${char}" ${filename} | wc -l`,"
done
Lo script genera questo:
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,
MODIFICA dopo il commento
Per creare un ciclo per tutti i caratteri stampabili è possibile effettuare ciò:
#!/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
Questo conterà tutti i caratteri ANSI da 32 a 126 - questi sono i più comunemente leggibili. Si noti che questo non usa ignora maiuscole / minuscole.
l'output da questo sarà:
- 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
da grep. (nella tua domanda ne avevi solo 3 nel risultato atteso)
grep
ripetute all'intero input.
Ecco un'altra soluzione (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 '...'
: puoi dirlo direttamente awk '...' file
.
Il seguente perl
oneliner farà il conteggio. Inserisco la regex nel contesto dell'elenco (per ottenere il numero di corrispondenze) e lo inserisco nel contesto scalare:
$ 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"))'
Ecco una soluzione che utilizza 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]) + ','
Qui abbiamo usato la classe collections
del modulo Counter
per contare il numero di occorrenze di ciascun carattere, quindi ai fini della stampa abbiamo usato il string
modulo per ottenere tutte le lettere minuscole dalla variabile string.lowercase
.
Salvare lo script sopra in un file dandogli il nome desiderato ad es count.py
. Ora dalla stessa directory in cui viene salvato il file, è possibile eseguire semplicemente python count.py
per eseguire il file, da qualsiasi altra directory utilizzare il percorso assoluto del file per eseguirlo, ad es python /absolute/path/to/count.py
.
Qualche tempo fa ho scritto un programma C per farlo, perché ne avevo bisogno per guardare file di grandi dimensioni e produrre alcune statistiche.
#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;
}
compilare con (supponendo che il codice sorgente risieda in character-distribution.c
):
cc -std=c99 -O2 -g0 -o character-distribution character-distribution.c
Corri con:
./character-distribution < 1.txt
Se non hai un compilatore C pronto, installa GCC:
sudo apt-get install gcc build-essential
Soluzione simile a @heemayl, con codice più stretto, che funziona su Python 2.7 e 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))
La prima affermazione, count = collections.Counter(…)
fa tutto il vero lavoro.
fileinput.input()
legge ogni riga dell'input, che può essere reindirizzata tramite stdin o come argomenti della riga di comando.*
lo fa considerare un personaggio alla volta piuttosto che una linea alla volta.count = Counter(…)
conta le occorrenze di ciascun personaggio in modo efficiente, in un unico passaggio e memorizza il risultato nella count
variabile.La seconda riga stampa solo i risultati.
'{} - {}'.format(c, count[c] + count[c.upper()]) for c in string.ascii_lowercase
fa un elenco di ogni personaggio e il suo conteggio.print(',\n'.join(…))
lo mette nel formato desiderato: uno per riga, separato da virgole, ma nessuna virgola sull'ultima riga.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
Se hai una versione precedente di GNU awk puoi usarla for (c in b) print c, b[c]
.
Ecco la risposta usando ruby. Viene fatto cambiando la stringa in un elenco uniq dei diversi caratteri e usando il metodo count su ciascuno di essi.
#!/usr/bin/env ruby
String content = IO.read("1.txt")
content.split("").uniq.sort.each { |chr| puts( chr + ' - ' + content.count(chr).to_s) }