Groß im Vergleich: Case-Sensitivity von Ä bis Eszett
Ein Artikel von Jörg Rosenthal.
Getestet mit Lazarus 3.2 | FPC 3.2.2
In den wenigsten Fällen werden die Funktionen Upper– und LowerCase genutzt, um eine gewünschte Form von Groß- und Kleinschreibung wirklich auf dem Bildschirm auszugeben. Häufig wird es verwendet, um einen case-insensitiven Vergleich durchzuführen…
s := Trim( Edit1.Text );
if LowerCase(s) = 'start' then (* ...*) ;
Hat ein Anwender mit aktivierter Feststelltaste „sTART“ eingehämmert, kommt er in diesem Fall wegen des case-insensitiven Vergleichs trotzdem weiter.
Neben bekannten Funktionen wie UpperCase und AnsiUpperCase findet man in der Unit LazUTF8 überraschenderweise weitere Funktionen, die mit „UTF8-“ beginnen: UTF8UpperCase, UTF8LowerCase und UTF8StringReplace. Wir schauen uns einmal die Ergebnisse an …
Code | Ergebnis | Bemerkung |
---|---|---|
UpperCase('Süße') | SüßE | kleines ü und ß |
AnsiUpperCase('Süße') | SÜSSE | nicht SÜẞE |
UTF8UpperCase('Süße','de') | SÜSSE | nicht SÜẞE |
AnsiLowerCase('SÜSSE') | süsse | |
AnsiLowerCase('SÜẞE') | süße | aus Groß-ẞ wird Klein-ß |
UTF8LowerCase('SÜẞE','de') | süße | aus Groß-ẞ wird Klein-ß |
Die Beispiele demonstrieren mehrere Aspekte:
- UpperCase bzw. LowerCase kümmern sich nur um ASCII-Buchstaben, aber nicht um Umlaute.
- Umlaute und Eszett werden in der Ansi-Version AnsiUpperCase berücksichtigt – man benötigt also für die deutsche Sprache kein spezielles UTF8UpperCase.
- Doppel-S: In AnsiUpperCase und UTF8UpperCase wird das kleine „ß“ durch Doppel-S ersetzt. Diese Ersetzung wurde speziell für die deutsche Sprache implementiert, denn das Eszett wird ausschließlich im Deutschen verwendet.
Leider kann die Ersatzschreibung „SS“ nicht einfach per AnsiLowerCase rückgängig gemacht werden, weil nicht jedes Doppel-S zu einem Eszett wird, z.B. bei „WASSER“ zu „Wasser“.
Das große „ẞ“ ist seit 2017 Bestandteil der offiziellen Rechtschreibung und wird seit 2020 anstelle des Doppel-S empfohlen. Diese Empfehlung wird jedoch in FreePascal noch nicht umgesetzt. Aber die Umwandlung von Groß-ẞ zu Klein-ß funktioniert problemlos.
Umlaute und Eszett richtig vergleichen
Möchte man Wörter mit ä,ö,ü miteinander vergleichen, genügt es die ANSI-Variante AnsiLowerCase oder AnsiUpperCase zu verwenden, welche die Umlaute berücksichtigen. Auch das Eszett wird berücksichtigt, jedoch ist dabei Vorsicht geboten…
s := Trim( Edit1.Text );
if AnsiLowerCase(s) = 'anstoßen' then (* ... *);
(* oder *)
s := Trim( Edit1.Text );
if AnsiUpperCase(s) = 'ANSTOSSEN' then (* ... *);
Beide if-Vergleiche funktionieren, wenn der Anwender „anstoßen“ oder „Anstoßen“ eingibt. Ist der Anwender jedoch in der Schweiz, wo kein „ß“ verwendet wird, gibt er wahrscheinlich ganz korrekt „anstossen“ ein – und dann schlägt der erste Vergleich fehl, weil ein „ß“ erwartet wird. Der zweite Vergleich funktioniert jedoch für alle Schreibweisen und ist deshalb vorzuziehen! Der Claim am Anfang dieses Artikels „Groß im Vergleich“ dient hier als Merksatz.
Anpassung an Türkisch
Es überrascht, in der Lazarus-Unit LazUTF8 die Funktionen UTF8LowerCase, UTF8UpperCase und UTF8StringReplace zu finden, denn auch AnsiUpperCase, AnsiLowerCase und StringReplace leisten anscheinend alles, was man braucht.
Die UTF8-Varianten haben jedoch einen optionalen Extra-Parameter für die Sprache des Textes, z.B. ‚tr‘ als Sprachcode für Türkisch. Der Grund ist, dass im Türkischen der Buchstabe „i“ in zwei Varianten existiert, was die Ansi-Funktionen nicht berücksichtigen. Diese Sonderbehandlung wird nur durchgeführt, wenn ‚tr‘ oder ‚az‘ als Sprache angegeben ist. Und UTF8StringReplace bezieht diese Besonderheit bei der Option rfIgnoreCase ebenfalls mit ein.
if UTF8UpperCase('istanbul', 'tr') = 'İSTANBUL' then (* ... *);
Nur die UTF8-Funktion mit der Sprachcode-Angabe ‚tr‘ macht aus dem ersten Zeichen „i“ das im Türkischen richtige „İ“ (groß und mit Punkt) und aus einem kleinen „ı“ (ohne Punkt) ein „I“.
Bezüglich der Benennung der Funktionen als „UTF8-„: Das Thema Groß- und Kleinschreibung hat eigentlich überhaupt nichts mit der UTF-8-Kodierung zu tun, sondern bedient eher die Internationalisierung. Man hätte die Anpassung für das türkische „i“ ebenso gut in UTF-16-Funktionen für UnicodeString einbauen können (wo sie nun fehlen), aber in Lazarus ist UTF-8 der Standard, weshalb sich wohl die Entwickler der Unit LazUTF8 der Sache angenommen haben.
Geschichtliches
Ursprünglich gab es im lateinischen Alphabet nur die Buchstaben, die wir heute als Großbuchstaben kennen und als Majuskeln (lateinisch: capitalis) bezeichnet werden. Die Kleinbuchstaben (Minuskeln) wurden ab dem Frühmittelalter entworfen, denn in Klöstern hatte man den Wunsch, mit Schreibfedern schneller schreiben zu können. Deshalb wurde die Schreibschrift entwickelt, in der überwiegend die geschwungenen und verbundenen Minuskeln verwendet werden. Für Setzereien (Buchdruck) und seit der Einführung von Schreibmaschinen sind die zusätzlichen Kleinbuchstaben eigentlich kein Vorteil mehr. Allerdings sind die Minuskeln nicht nur seit tausend Jahren etabliert, sondern auch beim Lesen nützlich: die Kleinbuchstaben verbessern die Lesbarkeit langer Texte ganz deutlich. Und speziell im Deutschen, wo Substantive mit einem Großbuchstaben beginnen, gibt es zudem einen kleinen Vorteil durch schnelleres Erkennen wichtiger Wörter im Text. Übrigens, der Begriff „upper case“ bezog sich in einer Setzerei auf das obere Fach des Setzkastens, wo die großen Drucklettern aufbewahrt wurden. Das „lower case“ war das untere Fach mit den kleinen Lettern. |
Fazit zu AnsiUpperCase
Bewegt man sich mit seinem Programm sprachlich nur im westeuropäischen Raum, genügt AnsiUpperCase für case-insensitive Vergleiche. Ob sich die Ansi-Variante auch zuverlässig z.B. für das griechische oder kyrillische Alphabet eignet, konnte ich noch nicht in Erfahrung bringen.
Wenn man Texte auf internationaler Ebene verarbeitet, sollte man sicherheitshalber auf UTF8UpperCase zurückgreifen. Allerdings ergibt das nur Sinn, wenn man den Sprachcode, z.B. ‚tr‘, des jeweiligen Text-Inhalts kennt, denn sonst verhält sich UTF8UpperCase nicht anders als AnsiUpperCase.