std.unicode
Unicode-Korrektheit kostet Platz: Die Tabellen aus UnicodeData.txt sind groß. Deshalb steckt sie nicht in std.text, sondern in dieser Unit, die man bewusst dazuholt. Wer nur UTF-8 zählen und schneiden will, zahlt nichts dafür.
std.unicode liefert:
- Normalisierung NFD, NFC, NFKD, NFKC — vollständige kanonische und Kompatibilitäts-Dekomposition, kanonische Sortierung der Kombinationszeichen, Komposition mit korrektem Blocking, Hangul algorithmisch
- Normalisierendes Vergleichen:
TextEqualsNormalized,TextCompareNormalized,TextStartsWithNormalized - Groß-/Kleinschreibung auf Codepoint- und
Text-Ebene — regelbasiert für ASCII und Latin-1 - Klassifizierung: Unicode-Whitespace, ASCII-Ziffer/-Buchstabe, dazu Unicode-bewusstes Trimmen
Die Tabellen liegen in der generierten Unit std.unicode_data (aus UnicodeData.txt), die dieser Unit gehört und nicht direkt benutzt wird.
Autor: Andreas Röne
Copyright: 2024-2026 Andreas Röne
→ std.text · std.unicode_case · std.grapheme · Standard Library
Normalisierung
Dasselbe Schriftbild kann verschieden kodiert sein: „é„ als ein Codepoint U+00E9 (vorkomponiert) oder als e + Combining Acute U+0301 (zerlegt). Ein Bytevergleich hält beide für verschieden. Normalisierung bringt sie auf eine gemeinsame Form.
| Form | Bedeutung |
|---|---|
| NFD | Kanonische Dekomposition — alles zerlegt |
| NFC | Kanonische Dekomposition, danach Komposition — die kompakte Standardform |
| NFKD | Wie NFD, zusätzlich Kompatibilitäts-Zerlegung (fi → fi, ² → 2) |
| NFKC | Wie NFKD, danach Komposition |
import std.io;
import std.text;
import std.unicode;
// "e" + U+0301 (Combining Acute) aus Codepoints gebaut — als Literal
// geschrieben würde sich die zerlegte Form beim Kopieren still in die
// vorkomponierte verwandeln, und das Beispiel zeigte nichts mehr.
fn Zerlegt(): Text {
var buf: int64 := alloc(8);
var n: int64 := CodepointToUtf8(101, buf); // 'e'
n := n + CodepointToUtf8(769, buf + n); // U+0301
return TextFromUtf8(buf, n);
}
fn main(): int64 {
var a: Text := TextFromPchar("é"c); // U+00E9, vorkomponiert
var b: Text := Zerlegt();
PrintLn(IntToStr(a.ByteLength())); // 2
PrintLn(IntToStr(b.ByteLength())); // 3
PrintLn(IntToStr(a.Equals(b))); // 0 — Bytevergleich
PrintLn(IntToStr(TextEqualsNormalized(a, b))); // 1 — normalisiert gleich
var n: Text := TextToNFC(b);
PrintLn(IntToStr(n.ByteLength())); // 2
var d: Text := TextToNFD(a);
PrintLn(IntToStr(d.ByteLength())); // 3
return 0;
}
| Signatur | Beschreibung |
|---|---|
TextToNFD(t: Text): Text | Kanonische Dekomposition + kanonische Sortierung |
TextToNFC(t: Text): Text | NFD, danach kanonische Komposition |
TextToNFKD(t: Text): Text | Kompatibilitäts-Dekomposition |
TextToNFKC(t: Text): Text | NFKD, danach Komposition |
TextEqualsNormalized(a, b): int64 | Vergleich nach Normalisierung |
TextCompareNormalized(a, b): int64 | Lexikografisch nach Normalisierung: -1/0/1 |
TextStartsWithNormalized(t, prefix): int64 | Präfixtest nach Normalisierung |
Die 11.172 modernen Hangul-Silben (U+AC00–U+D7A3) werden algorithmisch zerlegt und zusammengesetzt (Unicode §3.12) — dafür braucht es keine Tabelle.
NFC vergleicht, NFKC vereinheitlicht. NFKC wirft Formatierungsunterschiede weg (fiundfiwerden gleich) und ist deshalb für Suchindizes und Bezeichner-Vergleiche gedacht, nicht zum Speichern von Nutzertext — die Umwandlung ist nicht umkehrbar.
Groß-/Kleinschreibung
| Signatur | Beschreibung |
|---|---|
UnicodeToUpper(cp: int64): int64 | Codepoint zu Groß — ASCII und Latin-1 Supplement |
UnicodeToLower(cp: int64): int64 | Codepoint zu Klein — ASCII und Latin-1 Supplement |
TextToUpper(t: Text): Text | Dekodieren → wandeln → neu kodieren |
TextToLower(t: Text): Text | dito |
Diese Umwandlung ist regelbasiert und reicht nur bis Latin-1. Griechisch, Kyrillisch und Latin Extended bleiben unverändert:TextToUpper("Straße Über")liefertSTRAßE ÜBER— dasßbleibt stehen, weil es keine 1:1-Großform hat.
Für die vollständige Abdeckungstd.unicode_caseverwenden (TextToUpperFull/TextToLowerFull). Die beiden Units sind bewusst getrennt: Beide bringen große generierte Tabellen mit, und zusammen übersetzt überschreitet das die Größengrenze des Compilers pro Übersetzungseinheit.
Klassifizierung und Trimmen
| Signatur | Beschreibung |
|---|---|
UnicodeIsWhitespace(cp: int64): int64 | Unicode-Eigenschaft White_Space — nicht nur ASCII |
UnicodeIsAsciiDigit(cp: int64): int64 | 0–9 |
UnicodeIsAsciiLetter(cp: int64): int64 | A–Z, a–z |
TextTrimUnicode(t: Text): Text | Unicode-Whitespace an beiden Enden entfernen |
TextTrimStartUnicode(t: Text): Text | nur vorn |
TextTrimEndUnicode(t: Text): Text | nur hinten |
Der Unterschied zu Text.Trim(): Jenes kennt nur ASCII-Whitespace. Diese Funktionen entfernen auch geschütztes Leerzeichen, Halbgeviert-Abstand und die übrigen Zeichen mit der Eigenschaft White_Space — genau das, was aus kopiertem Text von Webseiten hereinkommt.
Letzte Aktualisierung: 2026-08-11
