Recientemente comencé a escribir un juego en el que construyes palabras usando mosaicos de letras. Para crear el juego, necesitaba saber la frecuencia de las letras en las palabras regulares del idioma inglés, para poder presentar un conjunto útil de mosaicos de letras. La frecuencia de las letras se discute en varios lugares, incluso en Wikipedia, pero quería calcular la frecuencia de las letras yo mismo.
Linux proporciona una lista de palabras en el /usr/share/dict/words
archivo, por lo que ya tengo una lista de palabras probables para usar. Las words
El archivo contiene muchas palabras que quiero, pero algunas que no. Quería una lista de todas las palabras que no fueran palabras compuestas (sin guiones ni espacios) o nombres propios (sin letras mayúsculas). Para obtener esa lista, puedo ejecutar grep
Comando para extraer solo las líneas que consisten únicamente en letras minúsculas:
$ grep '^[a-z]*$' /usr/share/dict/words
Esta expresión regular pregunta grep
para hacer coincidir patrones que son solo letras minúsculas. Los caracteres ^
y $
en el patrón representan el inicio y el final de la línea, respectivamente. El [a-z]
la agrupación coincidirá solo con las letras minúsculas a a z .
Aquí hay una muestra rápida de la salida:
$ grep '^[a-z]*$' /usr/share/dict/words | cabeza
a
aa
aaa
aah
aahed
aahing
aahs
aal
aalii
aaliis
Más recursos de Linux
- Hoja de trucos de los comandos de Linux
- Hoja de trucos de comandos avanzados de Linux
- Curso en línea gratuito:Descripción general técnica de RHEL
- Hoja de trucos de red de Linux
- Hoja de trucos de SELinux
- Hoja de trucos de los comandos comunes de Linux
- ¿Qué son los contenedores de Linux?
- Nuestros últimos artículos sobre Linux
Y sí, todas esas son palabras válidas. Por ejemplo, "aahed" es la exclamación en tiempo pasado de "aah", como en relajación. Y un "aalii" es un arbusto tropical espeso.
Ahora solo necesito escribir un gawk
script para hacer el trabajo de contar las letras en cada palabra, y luego imprimir la frecuencia relativa de cada letra que encuentra.
Contar letras
Una forma de contar letras en gawk
es iterar a través de cada carácter en cada línea de entrada y contar las apariciones de cada letra a a z . El substr
La función devolverá una subcadena de una longitud dada, como una sola letra, de una cadena más grande. Por ejemplo, este ejemplo de código evaluará cada carácter c
de la entrada:
{
largo =largo($0); for (i =1; i <=len; i++) {
c =substr($0, i, 1);
}
}
Si empiezo con una cadena global LETTERS
que contiene el alfabeto, puedo usar el index
función para encontrar la ubicación de una sola letra en el alfabeto. Ampliaré el gawk
ejemplo de código para evaluar solo las letras a a z en la entrada:
COMENZAR { LETRAS ="abcdefghijklmnopqrstuvwxyz" }
{
len =longitud($0); for (i =1; i <=len; i++) {
c =substr($0, i, 1);
ltr =índice(LETRAS, c);
}
>/pre>Tenga en cuenta que la función de índice devuelve la primera aparición de la letra de
LETTERS
cadena, comenzando con 1 en la primera letra, o cero si no se encuentra. Si tengo una matriz de 26 elementos, puedo usar la matriz para contar las ocurrencias de cada letra. Agregaré esto a mi ejemplo de código para incrementar (usando++
) el recuento de cada letra tal como aparece en la entrada:COMENZAR { LETRAS ="abcdefghijklmnopqrstuvwxyz" }
{
len =longitud($0); for (i =1; i <=len; i++) {
c =substr($0, i, 1);
ltr =índice(LETRAS, c);
if (ltr> 0) {
++cuenta[ltr];
}
}
}Impresión de frecuencia relativa
Después del
gawk
script cuenta todas las letras, quiero imprimir la frecuencia de cada letra que encuentra. No me interesa el número total de cada letra de la entrada, sino la frecuencia relativa de cada letra. La frecuencia relativa escala los conteos para que la letra con menos ocurrencias (como la letra q ) se establece en 1, y las demás letras son relativas a eso.Comenzaré con el conteo de la letra a , luego compare ese valor con los recuentos de cada una de las otras letras b a z :
FIN {
min =recuento[1]; for (ltr =2; ltr <=26; ltr++) {
if (contar[ltr]min =contar[ltr];
}
}
}Al final de ese bucle, la variable
min
contiene el recuento mínimo para cualquier letra. Puedo usar eso para proporcionar una escala para los conteos para imprimir la frecuencia relativa de cada letra. Por ejemplo, si la letra con la ocurrencia más baja es q , luegomin
será igual a la q contar.Luego recorro cada letra y la imprimo con su frecuencia relativa. Divido cada cuenta por
min
para imprimir la frecuencia relativa, lo que significa que la letra con el recuento más bajo se imprimirá con una frecuencia relativa de 1. Si otra letra aparece con el doble de frecuencia que el recuento más bajo, esa letra tendrá una frecuencia relativa de 2. Solo estoy interesado en valores enteros aquí, por lo que 2.1 y 2.9 son lo mismo que 2 para mis propósitos:FIN {
min =recuento[1]; for (ltr =2; ltr <=26; ltr++) {
if (contar[ltr]min =contar[ltr];
}
}
for (ltr =1; ltr <=26; ltr++) {
print substr(LETRAS, ltr, 1), int(cuenta[ltr] / min);
}
}Poniéndolo todo junto
Ahora tengo un
gawk
script que puede contar la frecuencia relativa de letras en su entrada:#!/usr/bin/gawk -f
# solo cuenta a-z, ignora A-Z y cualquier otro carácter
BEGIN { LETTERS ="abcdefghijklmnopqrstuvwxyz" }
{
largo =largo($0); for (i =1; i <=len; i++) {
c =substr($0, i, 1);
ltr =índice(LETRAS, c);
if (ltr> 0) {
++count[ltr];
}
}
}
# imprime la frecuencia relativa de cada letra
FIN {
min =recuento[1]; for (ltr =2; ltr <=26; ltr++) {
if (contar[ltr]min =contar[ltr];
}
}
for (ltr =1; ltr <=26; ltr++) {
print substr(LETRAS, ltr, 1), int(cuenta[ltr] / min);
}
}Lo guardaré en un archivo llamado
letter-freq.awk
para que pueda usarlo más fácilmente desde la línea de comandos.Si lo prefiere, también puede usar
chmod +x
para hacer que el archivo sea ejecutable por sí mismo. El#!/usr/bin/gawk -f
en la primera línea significa que Linux lo ejecutará como un script usando/usr/bin/gawk
programa. Y porque elgawk
la línea de comando usa-f
para indicar qué archivo debe usar como secuencia de comandos, necesita colgar-f
de modo que ejecutarletter-freq.awk
en el shell se interpretará correctamente como ejecutando/usr/bin/gawk -f letter-freq.awk
en su lugar.Puedo probar el script con algunas entradas simples. Por ejemplo, si introduzco el alfabeto en mi
gawk
script, cada letra debe tener una frecuencia relativa de 1:$ echo abcdefghijklmnopqrstuvwxyz | gawk -f frecuencia-letra.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 1Repitiendo ese ejemplo pero agregando una instancia adicional de la letra e imprimirá la letra e con una frecuencia relativa de 2 y cualquier otra letra como 1:
$ echo abcdeefghijklmnopqrstuvwxyz | gawk -f frecuencia-letra.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¡Y ahora puedo dar el gran paso! Usaré el
grep
comando con/usr/share/dict/words
archivar e identificar la frecuencia de letras para todas las palabras escritas completamente con letras minúsculas:$ grep '^[a-z]*$' /usr/share/dict/words | gawk -f frecuencia-letra.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 2De todas las palabras en minúsculas en
/usr/share/dict/words
archivo, las letras j , q y x ocurren con menor frecuencia. La letra z también es bastante raro. No en vano, la letra e es el más utilizado.