Par exemple, j'ai un fichier 1.txtcontenant:
Moscow
Astana
Tokyo
Ottawa
Je veux compter le nombre de tous les caractères comme:
a - 4,
b - 0,
c - 1,
...
z - 0
Par exemple, j'ai un fichier 1.txtcontenant:
Moscow
Astana
Tokyo
Ottawa
Je veux compter le nombre de tous les caractères comme:
a - 4,
b - 0,
c - 1,
...
z - 0
Réponses:
Vous pouvez utiliser ceci:
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 sedpartie place une nouvelle ligne après chaque personnage. Ensuite, nous sortsortons par ordre alphabétique. Et uniqcompte enfin le nombre d'occurrences. Le -idrapeau de uniqpeut être omis si vous ne voulez pas insensibilité à la casse.
sort -k 2pour les répertorier de manière alphanumérique.
sed -e $'s/\(.\)/\\1\\\n/g'(voir aussi stackoverflow.com/a/18410122/179014 )
| sort -rnk 1. Et si vous avez affaire à de très gros fichiers, comme moi, vous pouvez simplement échantillonner quelques milliers de lignes pour obtenir un proxy pour les cat 1.txt | shuf -n 10000 | sed 's/\(.\)/\1\n/g' | sort | uniq -ic | sort -rnk 1
Un peu en retard, mais pour compléter l'ensemble, une autre approche python (3), résultat trié:
#!/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
Lisez le fichier, sautez les espaces et retournez comme "caractères":
chars = open(sys.argv[1]).read().strip().replace("\n", "")Créez un ensemble (trié) d'uniques:
sorted(set([c for c in chars]))Comptez et imprimez l'occurrence pour chacun des caractères:
print(c+" -", chars.count(c)) for c in <uniques>chars_count.pyExécutez-le avec le fichier comme argument soit:
/path/to/chars_count.py </path/to/file>
si le script est exécutable, ou:
python3 /path/to/chars_count.py </path/to/file>
si ce n'est pas
Par défaut dans awk le F ield S eparator (FS) est un espace ou un onglet . Puisque nous voulons compter chaque caractère, nous devrons redéfinir le FS à rien ( FS="") pour diviser chaque caractère sur une ligne distincte et l'enregistrer dans un tableau et à la fin du END{..}bloc, imprimer leurs occurrences totales par la commande awk suivante :
$ 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="" ...bloc, nous divisons simplement les caractères. Et
en END{for (c in a) print c,a[c]}bloc, nous bouclons vers le tableau aet imprimons le caractère enregistré dedans print cet son nombre d'occurrencesa[c]
Faites une forboucle pour tous les caractères que vous souhaitez compter, et utilisez grep -iopour obtenir toutes les occurrences du caractère et de la casse ignorée, et wc -lpour compter les instances, et imprimer le résultat.
Comme ça:
#!/bin/bash
filename="1.txt"
for char in {a..z}
do
echo "${char} - `grep -io "${char}" ${filename} | wc -l`,"
done
Le script génère ceci:
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,
MODIFIER après commentaire
Pour créer une boucle pour tous les caractères imprimables, vous pouvez procéder comme suit:
#!/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
Cela comptera tous les caractères ANSI de 32 à 126 - ce sont les plus lisibles. Notez que cela n'utilise pas ignorer la casse.
la sortie de ceci sera:
- 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,
idu grep. (dans votre question vous n'aviez que 3 dans le résultat attendu)
grepl'entrée entière à plusieurs reprises.
Voici une autre solution (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 '...': vous pouvez dire directement awk '...' file.
L' perloneliner suivant fera le décompte. Je mets l'expression régulière dans le contexte de la liste (pour obtenir le nombre de correspondances) et le mets dans un contexte scalaire:
$ 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"))'
Voici une solution utilisant 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]) + ','
Ici, nous avons utilisé la classe collectionsdu module Counterpour compter le nombre d'occurrences de chaque caractère, puis à des fins d'impression, nous avons utilisé le stringmodule pour obtenir toutes les lettres minuscules par la variable string.lowercase.
Enregistrez le script ci-dessus dans un fichier en lui donnant le nom que vous voulez, par exemple count.py. Maintenant, à partir du même répertoire où le fichier est enregistré, vous pouvez simplement exécuter python count.pypour exécuter le fichier, à partir de tout autre répertoire, utilisez le chemin absolu du fichier pour l'exécuter, c'est-à-dire python /absolute/path/to/count.py.
Il y a quelque temps, j'ai écrit un programme C pour cela, car j'en avais besoin pour regarder des fichiers volumineux et produire des statistiques.
#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;
}
compiler avec (en supposant que le code source réside character-distribution.c):
cc -std=c99 -O2 -g0 -o character-distribution character-distribution.c
courir avec:
./character-distribution < 1.txt
Si vous n'avez pas de compilateur C prêt, installez GCC:
sudo apt-get install gcc build-essential
Solution similaire à @heemayl, avec un code plus strict, qui fonctionne sur Python 2.7 et 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 première déclaration count = collections.Counter(…)fait tout le vrai travail.
fileinput.input() lit chaque ligne de l'entrée, qui peut être canalisée via stdin ou comme arguments de ligne de commande.* le fait considérer un personnage à la fois plutôt qu'une ligne à la fois.count = Counter(…)compte les occurrences de chaque caractère efficacement, en une seule passe, et stocke le résultat dans la countvariable.La deuxième ligne imprime simplement les résultats.
'{} - {}'.format(c, count[c] + count[c.upper()]) for c in string.ascii_lowercase fait une liste de chaque personnage et son nombre.print(',\n'.join(…)) le met au format souhaité: un par ligne, séparé par des virgules, mais pas de virgule sur la dernière ligne.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 vous avez une version antérieure de GNU awk, vous pouvez l'utiliser for (c in b) print c, b[c].
Voici la réponse en utilisant rubis. Cela se fait en changeant la chaîne en une liste uniq des différents caractères et en utilisant la méthode de comptage sur chacun d'eux.
#!/usr/bin/env ruby
String content = IO.read("1.txt")
content.split("").uniq.sort.each { |chr| puts( chr + ' - ' + content.count(chr).to_s) }