Buchstaben mit Umlauten
In Emmas Hofladen gibt es jetzt Äpfel und Kürbispüree, und Wörter wie diese brauchen besondere Aufmerksamkeit. Hier ist der Grund.
Ein Computer speichert einen Text als eine Reihe von Bytes, kleinen Zahlen von 0 bis 255. Die Texte in deinen Programmen verwenden, wie die meisten Texte der Welt, die Kodierung UTF-8: Jeder Buchstabe von a bis z, jede Ziffer, jedes Leerzeichen und jedes Satzzeichen belegt ein Byte, aber ein Buchstabe mit Umlaut, wie ä, ö oder ü, das ß und Buchstaben mit Akzent, wie é, belegen zwei (und manche Zeichen, etwa Emojis, vier). Luas Zeichenkettenfunktionen wissen nichts von Buchstaben: Sie zählen und schneiden Bytes. In einem Text ohne Umlaute ist ein Byte ein Zeichen, du merkst also nichts. Mit Umlauten merkst du es, und zwar an vier Stellen.
1. Länge. # und len zählen Bytes. Um Zeichen zu zählen, benutze utf8.len aus der Bibliothek utf8, die Lua genau dafür hat:
local wort = "Käse"
print(#wort, wort:len(), utf8.len(wort))Das gibt Folgendes aus:
5 5 42. Groß- und Kleinbuchstaben. upper und lower verändern nur die Buchstaben von a bis z; Umlaute bleiben, wie sie sind:
print(("Käse"):upper())
print(("KÜRBIS"):lower())Das gibt Folgendes aus:
KäSE
kÜrbisWenn du so ein Wort in Großbuchstaben brauchst, schreibe es im Code gleich so: "KÄSE".
3. Schneiden. Auch die Positionen in sub sind Bytes. In "Käse" belegt das ä die Positionen 2 und 3, die ersten beiden Buchstaben sind also sub(1, 3), und sub(1, 2) schneidet das ä in der Mitte durch:
local wort = "Käse"
print(wort:sub(1, 3))
print(wort:sub(1, 2))
print(wort:sub(1, 2) == "Kä")Das gibt Folgendes aus:
Kä
K�
falseEin halber Buchstabe ist überhaupt kein Zeichen, deshalb siehst du beim Ausgeben an seiner Stelle ein �. Dasselbe gilt für reverse, das die beiden Bytes jedes Umlauts vertauscht: ("Käse"):reverse() ergibt es��K. Schneiden ist sicher an Positionen, die dir find geliefert hat, denn auch sie sind Bytes, und mit negativen Positionen, wenn das Ende des Textes keine Umlaute hat.
4. Breiten. %-10s füllt einen Text auf 10 Bytes auf, ein Wort bekommt also für jeden Umlaut ein Leerzeichen zu wenig:
print(("%-10s|"):format("Karotten"))
print(("%-10s|"):format("Käse"))Das gibt Folgendes aus:
Karotten |
Käse |Die Lösung: Füge die Leerzeichen selbst hinzu, so viele wie die Breite minus die Zahl der Zeichen. Eine kleine Funktion erledigt das:
local function auffuellen(text, breite)
return text .. (" "):rep(breite - utf8.len(text))
end
print(auffuellen("Karotten", 10) .. "|")
print(auffuellen("Käse", 10) .. "|")Das gibt Folgendes aus:
Karotten |
Käse |Ist ein Text länger als die Breite, ist die Zahl negativ, und rep gibt einen leeren Text zurück; es wird also nichts abgeschnitten, genau wie bei %-10s.
Die Muster in der nächsten Übung haben mit Umlauten dasselbe Problem; du siehst es dort. Die Regel für alles: Texte mit Umlauten auszugeben, zu verbinden und zu durchsuchen ist immer in Ordnung. Wenn du zählst, schneidest, ausrichtest oder Buchstaben veränderst, denke an die Bytes.
So schreibst du es:
Anweisungen
- 1
Führe das Programm aus: Zwei Zeilen der Liste sind verschoben. Um zu sehen, warum, füge über der Liste eine eigene Schleife hinzu, die die Zahl der Zeichen jedes Namens ausgibt, gezählt mit
utf8.len:Karotten: 8 Äpfel: 5 Kürbispüree: 11 - 2
Repariere jetzt die Liste. Fülle jeden Namen nicht mit
%-14sauf, sondern selbst mitrepundutf8.lenauf 14 Zeichen auf; das Gewicht bleibt mit%6.2fformatiert. Die Liste steht dann untereinander:Karotten 12.50 kg Äpfel 2.00 kg Kürbispüree 6.75 kg