GNU/Linux >> Tutoriels Linux >  >> Linux

Utilisez awk pour calculer la fréquence des lettres

J'ai récemment commencé à écrire un jeu dans lequel vous construisez des mots à l'aide de tuiles de lettres. Pour créer le jeu, j'avais besoin de connaître la fréquence des lettres dans les mots réguliers de la langue anglaise, afin de pouvoir présenter un ensemble utile de tuiles de lettres. La fréquence des lettres est discutée à divers endroits, y compris sur Wikipédia, mais je voulais calculer moi-même la fréquence des lettres.

Linux fournit une liste de mots dans le /usr/share/dict/words fichier, j'ai donc déjà une liste de mots susceptibles d'être utilisés. Les words le fichier contient beaucoup de mots que je veux, mais quelques-uns que je ne veux pas. Je voulais une liste de tous les mots qui n'étaient pas des mots composés (pas de traits d'union ni d'espaces) ou des noms propres (pas de lettres majuscules). Pour obtenir cette liste, je peux exécuter le grep commande pour extraire uniquement les lignes composées uniquement de lettres minuscules :

$ grep  '^[a-z]*$' /usr/share/dict/words 

Cette expression régulière demande grep pour faire correspondre des modèles qui ne sont que des lettres minuscules. Les caractères ^ et $ dans le motif représentent respectivement le début et la fin de la ligne. Le [a-z] le groupement correspondra uniquement aux lettres minuscules a à z .

Voici un exemple rapide du résultat :

$ grep  '^[a-z]*$' /usr/share/dict/words | tête
a
aa
aaa
aah
aahed
aahing
aahs
aal
aalii
aaliis

Plus de ressources Linux

  • Aide-mémoire des commandes Linux
  • Aide-mémoire des commandes Linux avancées
  • Cours en ligne gratuit :Présentation technique de RHEL
  • Aide-mémoire sur le réseau Linux
  • Aide-mémoire SELinux
  • Aide-mémoire sur les commandes courantes de Linux
  • Que sont les conteneurs Linux ?
  • Nos derniers articles Linux

Et oui, ce sont tous des mots valables. Par exemple, "aahed" est l'exclamation au passé de "aah", comme dans la relaxation. Et un "aalii" est un arbuste tropical touffu.

Il ne me reste plus qu'à écrire un gawk script pour faire le travail de comptage des lettres dans chaque mot, puis imprimer la fréquence relative de chaque lettre qu'il trouve.

Compter les lettres

Une façon de compter les lettres dans gawk consiste à parcourir chaque caractère de chaque ligne d'entrée et à compter les occurrences de chaque lettre a à z . Le substr renverra une sous-chaîne d'une longueur donnée, telle qu'une seule lettre, à partir d'une chaîne plus grande. Par exemple, cet exemple de code évaluera chaque caractère c depuis l'entrée :

{
    longueur =longueur($0); for (i =1; i <=len; i++) {
        c =substr($0, i, 1);
    }
}

Si je commence par une chaîne globale LETTERS qui contient l'alphabet, je peux utiliser l'index fonction pour trouver l'emplacement d'une seule lettre dans l'alphabet. Je vais développer le gawk exemple de code pour évaluer uniquement les lettres a à z dans l'entrée :

BEGIN { LETTERS ="abcdefghijklmnopqrstuvwxyz" }
 
{
    len =length($0); for (i =1; i <=len; i++) {
        c =substr($0, i, 1);
        ltr =index(LETTERS, c);
    }
}

Notez que la fonction index renvoie la première occurrence de la lettre de LETTERS chaîne, commençant par 1 à la première lettre, ou zéro s'il n'est pas trouvé. Si j'ai un tableau de 26 éléments, je peux utiliser le tableau pour compter les occurrences de chaque lettre. Je vais ajouter ceci à mon exemple de code pour incrémenter (en utilisant ++ ) le nombre de chaque lettre tel qu'il apparaît dans l'entrée :

BEGIN { LETTERS ="abcdefghijklmnopqrstuvwxyz" }
 
{
    len =length($0); for (i =1; i <=len; i++) {
        c =substr($0, i, 1);
        ltr =index(LETTERS, c);
 
if (ltr> 0) {
            ++count[ltr];
        }
    }
}

Fréquence relative d'impression

Après le gawk le script compte toutes les lettres, je veux imprimer la fréquence de chaque lettre qu'il trouve. Je ne suis pas intéressé par le nombre total de chaque lettre de l'entrée, mais plutôt par la fréquence relative de chaque lettre. La fréquence relative met à l'échelle les comptes de sorte que la lettre avec le moins d'occurrences (comme la lettre q ) est défini sur 1, et les autres lettres sont relatives à cela.

Je vais commencer par le décompte pour la lettre a , puis comparez cette valeur aux décomptes pour chacune des autres lettres b à z :

END {
    min =count[1] ; for (ltr =2; ltr <=26; ltr++) {
        if (count[ltr]             min =count[ltr];
        }
    }
}

A la fin de cette boucle, la variable min contient le nombre minimum pour n'importe quelle lettre. Je peux l'utiliser pour fournir une échelle pour les comptes afin d'imprimer la fréquence relative de chaque lettre. Par exemple, si la lettre avec l'occurrence la plus basse est q , puis min sera égal au q compter.

Ensuite, je parcours chaque lettre et je l'imprime avec sa fréquence relative. Je divise chaque compte par min pour imprimer la fréquence relative, ce qui signifie que la lettre avec le nombre le plus bas sera imprimée avec une fréquence relative de 1. Si une autre lettre apparaît deux fois plus souvent que le nombre le plus bas, cette lettre aura une fréquence relative de 2. Je suis seulement intéressé par les valeurs entières ici, donc 2.1 et 2.9 sont les mêmes que 2 pour mes besoins :

END {
    min =count[1] ; for (ltr =2; ltr <=26; ltr++) {
        if (count[ltr]             min =count[ltr];
        }
    }
 
    for (ltr =1; ltr <=26; ltr++) {
        print substr(LETTERS, ltr, 1), int(count[ltr] / min);
    }
}

Tout mettre ensemble

Maintenant j'ai un gawk script qui peut compter la fréquence relative des lettres dans son entrée :

#!/usr/bin/gawk -f
 
# compte uniquement a-z, ignore A-Z et tout autre caractère
 
BEGIN { LETTERS ="abcdefghijklmnopqrstuvwxyz" }
 
{
    longueur =longueur($0); for (i =1; i <=len; i++) {
        c =substr($0, i, 1);
        ltr =index(LETTERS, c);
 
if (ltr> 0) {
           ++count[ltr] ;
        }
    }
}
 
# affiche la fréquence relative de chaque lettre
   
FIN {
    min =count[1] ; for (ltr =2; ltr <=26; ltr++) {
        if (count[ltr]             min =count[ltr];
        }
    }
 
    for (ltr =1; ltr <=26; ltr++) {
        print substr(LETTERS, ltr, 1), int(count[ltr] / min);
    }
}

Je vais enregistrer cela dans un fichier appelé letter-freq.awk afin que je puisse l'utiliser plus facilement depuis la ligne de commande.

Si vous préférez, vous pouvez également utiliser chmod +x pour rendre le fichier exécutable par lui-même. Le #!/usr/bin/gawk -f sur la première ligne signifie que Linux l'exécutera en tant que script en utilisant le /usr/bin/gawk programme. Et parce que le gawk la ligne de commande utilise -f pour indiquer quel fichier il doit utiliser comme script, vous avez besoin de ce -f suspendu de sorte que l'exécution de letter-freq.awk au niveau du shell sera correctement interprété comme exécutant /usr/bin/gawk -f letter-freq.awk à la place.

Je peux tester le script avec quelques entrées simples. Par exemple, si j'introduis l'alphabet dans mon gawk script, chaque lettre doit avoir une fréquence relative de 1 :

$ echo abcdefghijklmnopqrstuvwxyz | gawk -f lettre-freq.awk
a 1
b 1
c 1
d 1
e 1
f 1
g 1
h 1
i 1
j 1
k 1
l 1
m 1
n 1
o 1
p 1
q 1
r 1
s 1
t 1
u 1
v 1
w 1
x 1
y 1
z 1

Répétition de cet exemple mais en ajoutant une instance supplémentaire de la lettre e imprimera la lettre e avec une fréquence relative de 2 et toutes les autres lettres comme 1 :

$ echo abcdeefghijklmnopqrstuvwxyz | gawk -f lettre-freq.awk
a 1
b 1
c 1
d 1
e 2
f 1
g 1
h 1
i 1
j 1
k 1
l 1
m 1
n 1
o 1
p 1
q 1
r 1
s 1
t 1
u 1
v 1
w 1
x 1
y 1
z 1

Et maintenant, je peux faire le grand pas ! Je vais utiliser le grep commande avec le /usr/share/dict/words fichier et identifiez la fréquence des lettres pour tous les mots entièrement écrits en minuscules :

$ grep  '^[a-z]*$' /usr/share/dict/words | gawk -f lettre-freq.awk
a 53
b 12
c 28
d 21
e 72
f 7
g 15
h 17
i 58
j 1
k 5
l 36
m 19
n 47
o 47
p 21
q 1
r 46
s 48
t 44
u 25
v 6
w 4
x 1
y 13
z 2

De tous les mots en minuscules dans le /usr/share/dict/words fichier, les lettres j , q , et x surviennent le moins fréquemment. La lettre z est aussi assez rare. Sans surprise, la lettre e est le plus fréquemment utilisé.


Linux
  1. Comment utiliser BusyBox sous Linux

  2. Comment j'utilise cron sous Linux

  3. Un guide du débutant pour rester bouche bée

  4. Comment utiliser Awk pour imprimer uniquement les lignes contenant 5 colonnes ?

  5. Impossible d'utiliser le gouverneur cpufreq de l'espace utilisateur et de définir la fréquence du processeur

Pourquoi j'utilise rxvt comme terminal

Commande Awk sous Linux

Utiliser l'éditeur vi

Comment utiliser Instagram dans le terminal

Comment utiliser la commande PS

Comment utiliser la commande TOP