GNU/Linux >> Tutoriales Linux >  >> Linux

Usa awk para calcular la frecuencia de las letras

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 , luego min 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 el gawk la línea de comando usa -f para indicar qué archivo debe usar como secuencia de comandos, necesita colgar -f de modo que ejecutar letter-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 1

Repitiendo 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 2

De 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.


Linux
  1. Cómo usar BusyBox en Linux

  2. Cómo uso cron en Linux

  3. Cómo usar expresiones Awk y regulares para filtrar texto o cadenas en archivos

  4. Cómo usar Nginx para redirigir

  5. Variable externa en Awk?

Por qué uso rxvt como mi terminal

Comando Awk en Linux

Usar el editor vi

Cómo usar Instagram en la terminal

Cómo usar el comando PS

Cómo usar el comando SUPERIOR