Advertisements

Verwenden Sie awk, um die Buchstabenhäufigkeit zu berechnen

Ich habe vor kurzem angefangen, ein Spiel zu schreiben, in dem Sie Wörter mit Buchstabenkacheln bilden. Um das Spiel zu erstellen, musste ich die Häufigkeit von Buchstaben in normalen Wörtern in der englischen Sprache kennen, damit ich einen nützlichen Satz von Buchstabenkacheln präsentieren konnte. Die Briefhäufigkeit wird an verschiedenen Stellen diskutiert, auch auf Wikipedia, aber ich wollte die Briefhäufigkeit selbst berechnen.

Linux bietet eine Liste von Wörtern im /usr/share/dict/words Datei, daher habe ich bereits eine Liste mit wahrscheinlichen Wörtern. Der words Datei enthält viele Wörter, die ich möchte, aber einige, die ich nicht möchte. Ich wollte eine Liste aller Wörter, die keine zusammengesetzten Wörter (keine Bindestriche oder Leerzeichen) oder Eigennamen (keine Großbuchstaben) sind. Um diese Liste zu erhalten, kann ich die grep Befehl, um nur die Zeilen herauszuziehen, die ausschließlich aus Kleinbuchstaben bestehen:

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

Dieser reguläre Ausdruck fragt grep um Muster abzugleichen, die nur aus Kleinbuchstaben bestehen. Die Charaktere ^ und $ im Muster den Anfang bzw. das Ende der Linie darstellen. Der [a-z] Gruppierung entspricht nur den Kleinbuchstaben ein zu mit.

Hier ist ein kurzes Beispiel der Ausgabe:

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

Weitere Linux-Ressourcen

Und ja, das sind alles gültige Worte. Zum Beispiel ist „aahed“ der Ausruf der Vergangenheitsform von „aah“, wie in Entspannung. Und ein “Aalii” ist ein buschiger tropischer Strauch.

Jetzt muss ich nur noch a . schreiben gawk Skript, um die Buchstaben in jedem Wort zu zählen und dann die relative Häufigkeit jedes gefundenen Buchstabens auszugeben.

Buchstaben zählen

Eine Möglichkeit, Buchstaben zu zählen gawk besteht darin, jedes Zeichen in jeder Eingabezeile zu durchlaufen und das Vorkommen jedes Buchstabens zu zählen ein zu mit. Der substr -Funktion gibt eine Teilzeichenfolge einer bestimmten Länge, z. B. einen einzelnen Buchstaben, aus einer größeren Zeichenfolge zurück. Dieses Codebeispiel wertet beispielsweise jedes Zeichen aus c aus der Eingabe:

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

Wenn ich mit einem globalen String beginne LETTERS das das Alphabet enthält, kann ich das verwenden index Funktion, um die Position eines einzelnen Buchstabens im Alphabet zu finden. Ich erweitere die gawk Codebeispiel um nur die Buchstaben auszuwerten ein zu mit in der eingabe:

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

Beachten Sie, dass die Indexfunktion das erste Vorkommen des Buchstabens aus dem zurückgibt LETTERS Zeichenfolge, beginnend mit 1 am ersten Buchstaben oder Null, wenn sie nicht gefunden wird. Wenn ich ein Array mit 26 Elementen habe, kann ich das Array verwenden, um die Vorkommen jedes Buchstabens zu zählen. Ich werde dies zu meinem Codebeispiel hinzufügen, um zu inkrementieren (mit ++) die Anzahl für jeden Buchstaben, wie er in der Eingabe erscheint:

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

Relative Häufigkeit drucken

Nach dem gawk script zählt alle Buchstaben, ich möchte die Häufigkeit jedes gefundenen Buchstabens ausgeben. Mich interessiert nicht die Gesamtzahl jedes Buchstabens aus der Eingabe, sondern die relative Frequenz jedes Buchstabens. Die relative Häufigkeit skaliert die Zählungen so, dass der Buchstabe mit den wenigsten Vorkommen (wie der Buchstabe Q) ist auf 1 gesetzt und andere Buchstaben sind relativ dazu.

Ich fange mit der Zählung für den Brief an ein, dann vergleiche diesen Wert mit den Zählungen für jeden der anderen Buchstaben B zu mit:

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

Am Ende dieser Schleife ist die Variable min enthält die Mindestanzahl für jeden Buchstaben. Ich kann das verwenden, um eine Skala für die Zählungen bereitzustellen, um die relative Häufigkeit jedes Buchstabens zu drucken. Wenn beispielsweise der Buchstabe mit der geringsten Häufigkeit . ist Q, dann min wird gleich sein Q zählen.

Dann durchlaufe ich jeden Buchstaben und drucke ihn mit seiner relativen Häufigkeit. Ich dividiere jede Zählung durch min um die relative Häufigkeit zu drucken, d. h. der Buchstabe mit der niedrigsten Anzahl wird mit einer relativen Häufigkeit von 1 gedruckt. Wenn ein anderer Buchstabe doppelt so oft wie die niedrigste Anzahl vorkommt, hat dieser Buchstabe eine relative Häufigkeit von 2. Ich bin nur interessiert sich hier für ganzzahlige Werte, also sind 2.1 und 2.9 für meine Zwecke dasselbe wie 2.

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

Alles zusammenfügen

Jetzt habe ich ein gawk Skript, das die relative Häufigkeit von Buchstaben in seiner Eingabe zählen kann:

#!/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);
    }
}

Ich speichere das in einer Datei namens letter-freq.awk damit ich es einfacher von der Befehlszeile aus verwenden kann.

Wenn Sie möchten, können Sie auch chmod +x um die Datei eigenständig ausführbar zu machen. Der #!/usr/bin/gawk -f in der ersten Zeile bedeutet, dass Linux es als Skript mit dem /usr/bin/gawk Programm. Und weil die gawk Befehlszeile verwendet -f um anzugeben, welche Datei als Skript verwendet werden soll, müssen Sie das hängen -f damit die Ausführung letter-freq.awk an der Shell wird richtig als ausgeführt interpretiert /usr/bin/gawk -f letter-freq.awk stattdessen.

Ich kann das Skript mit ein paar einfachen Eingaben testen. Wenn ich zum Beispiel das Alphabet in mein gawk Skript sollte jeder Buchstabe eine relative Häufigkeit von 1 haben:

$ 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

Dieses Beispiel wiederholen, aber eine zusätzliche Instanz des Buchstabens hinzufügen e werde den Brief drucken e mit einer relativen Häufigkeit von 2 und jedem zweiten Buchstaben als 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

Und jetzt kann ich den großen Schritt machen! Ich werde die verwenden grep Befehl mit dem /usr/share/dict/words Datei und identifizieren Sie die Buchstabenhäufigkeit für alle Wörter, die ausschließlich mit Kleinbuchstaben geschrieben sind:

$ 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

Von allen kleingeschriebenen Wörtern im /usr/share/dict/words Datei, die Buchstaben J, Q, und x kommen am seltensten vor. Der Buchstabe mit ist auch ziemlich selten. Es überrascht nicht, dass der Brief e wird am häufigsten verwendet.

Verwenden Sie awk, um die Buchstabenhäufigkeit zu berechnen

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to top