web-dev-qa-db-fra.com

Comment compter les occurrences de chaque personnage?

Par exemple, j'ai le fichier 1.txt, qui contient:

Moscow
Astana
Tokyo
Ottawa

Je veux compter le nombre de tous les caractères comme:

a - 4,
b - 0,
c - 1,
...
z - 0
13
Set-xx

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 partie sed place une nouvelle ligne après chaque caractère. Ensuite, nous sort la sortie par ordre alphabétique. Et enfin uniq compte le nombre d’occurrences. L'indicateur -i de uniq peut être omis si vous ne voulez pas que la casse soit respectée.

20
chaos

Un peu tard, 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

Explication

  1. Lisez le fichier, ignorez les espaces et retourne sous forme de "caractères":

    chars = open(sys.argv[1]).read().strip().replace("\n", "")
    
  2. Créez un ensemble (unique) de pièces uniques:

    sorted(set([c for c in chars]))
    
  3. Comptez et imprimez l'occurrence pour chacun des personnages:

    print(c+" -", chars.count(c)) for c in <uniques>
    

Comment utiliser

  1. Collez le code dans un fichier vide, enregistrez-le sous chars_count.py
  2. Exécutez-le avec le fichier comme argument de l'une des manières suivantes:

    /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

5
Jacob Vlijm

Par défaut dans awk le champ FS eparator (FS) est espace ou tab. Puisque nous voulons compter chaque caractère, nous devrons redéfinir le FS à rien (FS="") pour scinder chaque caractère sur une ligne distincte et l'enregistrer dans un tableau et à la fin du bloc insideEND{..}, afficher leur nombre total d'occurrences. 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

Dans le bloc {for (i=1;i<=NF;i++) a[$i]++} ... FS="" ..., nous divisons simplement les caractères. Et
dans le bloc END{for (c in a) print c,a[c]}, nous bouclons sur le tableau a et y imprimons le caractère enregistré print c et le nombre d’occurrences a[c]

5
αғsнιη

Voici une autre solution (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
  • Il crée un tableau associatif avec chaque caractère comme valeur d'index et le compte comme valeur de tableau.
  • L'action END affiche le tableau.
3
Howard H

Effectuez une boucle for pour tous les caractères à compter et utilisez grep -io pour obtenir toutes les occurrences du caractère et de la casse ignorée, et wc -l pour compter les occurrences 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 affiche 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,

EDIT after comment

Pour créer une boucle pour tous les caractères imprimables, procédez 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

Ceci 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,
3
stalet

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 collections du module Counter pour compter le nombre d'occurrences de chaque caractère, puis à des fins d'impression, nous avons utilisé le module string pour obtenir toutes les lettres minuscules à l'aide de la variable string.lowercase.

Enregistrez le script ci-dessus dans un fichier en lui donnant le nom de votre choix, par exemple. count.py. Maintenant, à partir du même répertoire où le fichier est enregistré, vous pouvez simplement exécuter python count.py pour exécuter le fichier. À partir de tout autre répertoire, utilisez le chemin absolu du fichier pour l’exécuter, c.-à-d. python /absolute/path/to/count.py.

2
heemayl

L’élément Perl suivant fera le décompte. Je mets la regex 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,
2
Sylvain Pineau

Il y a quelque temps, j’ai écrit un programme C pour le faire, car j’avais besoin de regarder les fichiers gros et de 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 dans 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
1
David Foerster

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 utiliser for (c in b) print c, b[c].

0
Steven Penny

Voici la réponse en utilisant Ruby. Cela se fait en changeant la chaîne en une liste uniq des différents caractères et en utilisant la méthode count 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) }
0
stalet

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 instruction, count = collections.Counter(…), effectue tout le travail réel.

  • fileinput.input() lit chaque ligne de l'entrée, qui peut être acheminée via stdin ou en tant qu'argument de ligne de commande.
  • * le fait considérer un caractère à la fois plutôt qu'une ligne à la fois.
  • count = Counter(…) compte les occurrences de chaque caractère efficacement, en un seul passage, et stocke le résultat dans la variable count.

La deuxième ligne affiche simplement les résultats.

  • '{} - {}'.format(c, count[c] + count[c.upper()]) for c in string.ascii_lowercase dresse une liste de chaque caractère et de son nombre.
  • print(',\n'.join(…)) le met dans le format souhaité: un par ligne, séparés par des virgules, mais pas de virgule sur la dernière ligne.
0
200_success