Por ejemplo, tengo un archivo 1.txt
que contiene:
Moscow
Astana
Tokyo
Ottawa
Quiero contar el número de todos los caracteres como:
a - 4,
b - 0,
c - 1,
...
z - 0
Por ejemplo, tengo un archivo 1.txt
que contiene:
Moscow
Astana
Tokyo
Ottawa
Quiero contar el número de todos los caracteres como:
a - 4,
b - 0,
c - 1,
...
z - 0
Respuestas:
Podrías usar esto:
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 coloca una nueva línea después de cada personaje. Luego salimos sort
alfabéticamente. Y por fin uniq
cuenta el número de ocurrencias. La -i
bandera de uniq
se puede omitir si no desea insensibilidad a mayúsculas y minúsculas.
sort -k 2
para enumerarlos alfanuméricamente.
sed -e $'s/\(.\)/\\1\\\n/g'
(ver también stackoverflow.com/a/18410122/179014 )
| sort -rnk 1
. Y si se trata de archivos muy grandes, como yo, solo puede probar algunos miles de líneas para obtener un proxy para los recuentos reales:cat 1.txt | shuf -n 10000 | sed 's/\(.\)/\1\n/g' | sort | uniq -ic | sort -rnk 1
Un poco tarde, pero para completar el conjunto, otro enfoque de python (3), resultado ordenado:
#!/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
Lea el archivo, saltee espacios y regrese como "caracteres":
chars = open(sys.argv[1]).read().strip().replace("\n", "")
Cree un conjunto (ordenado) de exclusivos:
sorted(set([c for c in chars]))
Cuente e imprima la aparición de cada uno de los personajes:
print(c+" -", chars.count(c)) for c in <uniques>
chars_count.py
Ejecútelo con el archivo como argumento por:
/path/to/chars_count.py </path/to/file>
si el script es ejecutable o:
python3 /path/to/chars_count.py </path/to/file>
si no lo es
Por defecto en awk el F ield S eparator (FS) es el espacio o pestaña . Como deseamos contar cada carácter, tendremos que redefinir el FS a cero ( FS=""
) para dividir cada carácter en una línea separada y guardarlo en una matriz y, al final dentro del END{..}
bloque, imprimir sus ocurrencias totales con el siguiente 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
En {for (i=1;i<=NF;i++) a[$i]++} ... FS="" ...
bloque simplemente dividimos los personajes. Y
en el END{for (c in a) print c,a[c]}
bloque estamos haciendo un bucle para agrupar a
e imprimir el carácter guardado en él print c
y su número de ocurrenciasa[c]
Haga un for
bucle para todos los caracteres que desea contar y grep -io
úselos para obtener todas las ocurrencias del personaje e ignorar mayúsculas y minúsculas, y wc -l
para contar instancias e imprimir el resultado.
Me gusta esto:
#!/bin/bash
filename="1.txt"
for char in {a..z}
do
echo "${char} - `grep -io "${char}" ${filename} | wc -l`,"
done
El script genera esto:
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,
EDITAR después del comentario
Para crear un bucle para todos los caracteres imprimibles, puede hacer esto:
#!/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
Esto contará todos los caracteres ANSI de 32 a 126; estos son los más legibles. Tenga en cuenta que esto no utiliza ignorar mayúsculas y minúsculas.
La salida de esto será:
- 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
del grep. (en su pregunta tenía solo 3 en el resultado esperado)
grep
toda la entrada repetidamente.
Aquí otra solución (en 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 '...'
: puedes decirlo directamente awk '...' file
.
El siguiente perl
oneliner hará el recuento. Puse la expresión regular en el contexto de la lista (para obtener el número de coincidencias) y lo puse en el contexto escalar:
$ 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"))'
Aquí hay una solución usando 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]) + ','
Aquí hemos usado la clase collections
del módulo Counter
para contar el número de ocurrencias de cada carácter, luego, para imprimir, hemos usado el string
módulo para obtener todas las letras minúsculas por la variable string.lowercase
.
Guarde el script anterior en un archivo con el nombre que desee, por ejemplo count.py
. Ahora desde el mismo directorio donde está guardado python count.py
el archivo, simplemente puede ejecutarlo para ejecutar el archivo, desde cualquier otro directorio use la ruta absoluta al archivo para ejecutarlo, es decir python /absolute/path/to/count.py
.
Hace un tiempo escribí un programa en C para hacer eso, porque lo necesitaba para mirar archivos grandes y producir algunas estadísticas.
#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;
}
compilar con (suponiendo que el código fuente reside en character-distribution.c
):
cc -std=c99 -O2 -g0 -o character-distribution character-distribution.c
corre con:
./character-distribution < 1.txt
Si no tiene un compilador de C listo, instale GCC:
sudo apt-get install gcc build-essential
Solución similar a @heemayl, con código más estricto, que funciona en Python 2.7 y 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 primera declaración count = collections.Counter(…)
hace todo el trabajo real.
fileinput.input()
lee cada línea de la entrada, que puede canalizarse a través de stdin o como argumentos de línea de comandos.*
hace que considere un carácter a la vez en lugar de una línea a la vez.count = Counter(…)
cuenta las ocurrencias de cada personaje de manera eficiente, en una sola pasada, y almacena el resultado en la count
variable.La segunda línea solo imprime los resultados.
'{} - {}'.format(c, count[c] + count[c.upper()]) for c in string.ascii_lowercase
hace una lista de cada personaje y su cuenta.print(',\n'.join(…))
lo pone en el formato deseado: uno por línea, separado por comas, pero sin coma en la última línea.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
Si tiene una versión anterior de GNU awk, puede usarla for (c in b) print c, b[c]
.
Aquí está la respuesta usando ruby. Se realiza cambiando la cadena en una lista uniq de los diferentes caracteres y utilizando el método de conteo en cada uno de ellos.
#!/usr/bin/env ruby
String content = IO.read("1.txt")
content.split("").uniq.sort.each { |chr| puts( chr + ' - ' + content.count(chr).to_s) }