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