GNU/Linux >> Linux Esercitazione >  >> Linux

Usa awk per calcolare la frequenza delle lettere

Di recente ho iniziato a scrivere un gioco in cui costruisci parole usando le tessere delle lettere. Per creare il gioco, dovevo conoscere la frequenza delle lettere sulle parole normali della lingua inglese, in modo da poter presentare un utile set di tessere delle lettere. La frequenza delle lettere è discussa in vari luoghi, incluso su Wikipedia, ma volevo calcolare io stesso la frequenza delle lettere.

Linux fornisce un elenco di parole in /usr/share/dict/words file, quindi ho già un elenco di parole probabili da usare. Le words file contiene molte parole che voglio, ma alcune che non voglio. Volevo un elenco di tutte le parole che non erano parole composte (senza trattini o spazi) o nomi propri (senza lettere maiuscole). Per ottenere quell'elenco, posso eseguire grep comando per estrarre solo le righe composte esclusivamente da lettere minuscole:

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

Questa espressione regolare chiede grep per abbinare i modelli che sono solo lettere minuscole. I caratteri ^ e $ nel modello rappresentano rispettivamente l'inizio e la fine della linea. Il [a-z] il raggruppamento corrisponderà solo alle lettere minuscole a a z .

Ecco un rapido esempio dell'output:

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

Più risorse Linux

  • Comandi Linux cheat sheet
  • Cheat sheet sui comandi avanzati di Linux
  • Corso online gratuito:Panoramica tecnica RHEL
  • Cheat sheet della rete Linux
  • Cheat sheet di SELinux
  • Cheat sheet dei comandi comuni di Linux
  • Cosa sono i container Linux?
  • I nostri ultimi articoli su Linux

E sì, quelle sono tutte parole valide. Ad esempio, "aahed" è l'esclamazione al passato di "aah", come in relax. E un "aalii" è un cespuglioso arbusto tropicale.

Ora devo solo scrivere un gawk script per eseguire il lavoro di conteggio delle lettere in ogni parola, quindi stampare la frequenza relativa di ogni lettera che trova.

Conteggio delle lettere

Un modo per contare le lettere in gawk consiste nell'iterare ogni carattere in ogni riga di input e contare le occorrenze di ogni lettera a a z . Il substr funzione restituirà una sottostringa di una determinata lunghezza, ad esempio una singola lettera, da una stringa più grande. Ad esempio, questo esempio di codice valuterà ogni carattere c dall'input:

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

Se inizio con una stringa globale LETTERS che contiene l'alfabeto, posso usare l'index funzione per trovare la posizione di una singola lettera dell'alfabeto. Espanderò il gawk esempio di codice per valutare solo le lettere a a z nell'input:

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

Nota che la funzione di indice restituisce la prima occorrenza della lettera da LETTERS stringa, che inizia con 1 alla prima lettera, o zero se non trovata. Se ho un array lungo 26 elementi, posso usare l'array per contare le occorrenze di ogni lettera. Lo aggiungerò al mio esempio di codice per incrementare (usando ++ ) il conteggio di ogni lettera così come appare nell'input:

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];
        }
    }
}

Frequenza relativa di stampa

Dopo il gawk lo script conta tutte le lettere, voglio stampare la frequenza di ogni lettera che trova. Non mi interessa il numero totale di ciascuna lettera dall'input, ma piuttosto la frequenza relativa di ogni lettera. La frequenza relativa ridimensiona i conteggi in modo che la lettera con il minor numero di occorrenze (come la lettera q ) è impostato su 1 e altre lettere sono relative a quello.

Inizierò con il conteggio della lettera a , quindi confronta quel valore con i conteggi per ciascuna delle altre lettere b a z :

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

Alla fine di quel ciclo, la variabile min contiene il conteggio minimo per ogni lettera. Posso usarlo per fornire una scala per i conteggi per stampare la frequenza relativa di ogni lettera. Ad esempio, se la lettera con l'occorrenza più bassa è q , quindi min sarà uguale a q contare.

Quindi apro ogni lettera e la stampo con la relativa frequenza. Divido ogni conteggio per min per stampare la frequenza relativa, il che significa che la lettera con il conteggio più basso verrà stampata con una frequenza relativa di 1. Se un'altra lettera appare due volte più spesso del conteggio più basso, quella lettera avrà una frequenza relativa di 2. Sono solo interessato a valori interi qui, quindi 2.1 e 2.9 sono gli stessi di 2 per i miei scopi:

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

Mettere tutto insieme

Ora ho un gawk script che può contare la frequenza relativa delle lettere nel suo input:

#!/usr/bin/gawk -f
 
# only count a-z, ignore A-Z and any other characters
 
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];
        }
    }
}
 
# print relative frequency of each letter
   
END {
    min = count[1]; for (ltr = 2; ltr <= 26; ltr++) {
        if (count[ltr] < min) {
            min = count[ltr];
        }
    }
 
    for (ltr = 1; ltr <= 26; ltr++) {
        print substr(LETTERS, ltr, 1), int(count[ltr] / min);
    }
}

Lo salverò in un file chiamato letter-freq.awk in modo da poterlo utilizzare più facilmente dalla riga di comando.

Se preferisci, puoi anche usare chmod +x per rendere il file eseguibile da solo. Il #!/usr/bin/gawk -f sulla prima riga significa che Linux lo eseguirà come script utilizzando /usr/bin/gawk programma. E perché il gawk la riga di comando usa -f per indicare quale file dovrebbe utilizzare come script, è necessario che sia sospeso -f in modo che l'esecuzione di letter-freq.awk alla shell verrà interpretato correttamente come in esecuzione /usr/bin/gawk -f letter-freq.awk invece.

Posso testare lo script con pochi semplici input. Ad esempio, se inserisco l'alfabeto nel mio gawk script, ogni lettera dovrebbe avere una frequenza relativa di 1:

$ echo abcdefghijklmnopqrstuvwxyz | gawk -f letter-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

Ripetendo quell'esempio ma aggiungendo un'istanza aggiuntiva della lettera e stamperà la lettera e con una frequenza relativa di 2 e ogni altra lettera come 1:

$ echo abcdeefghijklmnopqrstuvwxyz | gawk -f letter-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

E ora posso fare il grande passo! Userò il grep comando con il /usr/share/dict/words file e identifica la frequenza delle lettere per tutte le parole scritte interamente con lettere minuscole:

$ grep  '^[a-z]*$' /usr/share/dict/words | gawk -f letter-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

Di tutte le parole minuscole nel /usr/share/dict/words file, le lettere j , q e x si verificano meno frequentemente. La lettera z è anche piuttosto raro. Non a caso, la lettera e è il più utilizzato.


Linux
  1. Come utilizzare Awk e le espressioni regolari per filtrare testo o stringhe nei file

  2. Come utilizzare Nginx per reindirizzare

  3. Prima lettera maiuscola delle parole usando SED

  4. Usando grep vs awk

  5. Impossibile utilizzare il governatore cpufreq dello spazio utente e impostare la frequenza della cpu

Perché uso rxvt come terminale

Comando Awk in Linux

Usa vi Editor

Come utilizzare Instagram nel terminale

Come usare il comando PS

Come usare il comando TOP