Zusammenfassung
Ein std::string speichert Bytes, keine Buchstaben, und im heutigen Text kann ein Buchstabe ein bis vier Bytes belegen. Diese Lektion trennt drei Dinge, die die Alltagssprache verwechselt: das abstrakte Zeichen, das Unicode mit einer Zahl namens Codepunkt kennzeichnet; die Bytes, mit denen UTF-8 es kodiert; und die Gestalt, die der Bildschirm zeichnet. Sie erklärt, wie UTF-8 die Bits eines Codepunkts auf seine Bytes verteilt, warum das spanische Wort „año“ (Jahr) vier belegt und wie man die Zeichen einer Zeichenkette zählt, ohne sie zu dekodieren. Danach zeigt sie, welche Operationen den Text zerbrechen (Byte für Byte umkehren, Byte für Byte in Großbuchstaben umwandeln, mitten in einem Zeichen schneiden), welche ganz ohne Vorsicht funktionieren (speichern, kopieren, verketten, suchen, ausgeben) und was die Standardbibliothek von C++23 nicht leistet: Großbuchstaben außerhalb von ASCII, alphabetische Ordnung nach der Sprache, Normalisierung.
Lernziele
- Erklären, wie UTF-8 einen Codepunkt in einem bis vier Bytes kodiert, und die Bytes des „ñ“ von Hand dekodieren.
- Die Größe einer Zeichenkette mit Nicht-ASCII-Buchstaben in Bytes vorhersagen, etwa
"año"(4) oder"programación"(13). - Die Zeichen einer UTF-8-Zeichenkette zählen, indem man die Bytes zählt, die keine Folgebytes sind, mit der Bedingung
(c & 0xC0) != 0x80. - Die Operationen erkennen, die UTF-8-Text zerbrechen (Byte für Byte umkehren,
std::toupperpro Byte, mitten in einem Zeichen schneiden), und für jeden Fall entscheiden, was zu tun ist.
Zeichen, Codepunkte und Bytes
Drei Ebenen
Die Lektion Zeichen, boolesche Werte, Umwandlungen und Konstanten stellte char als ganze Zahl von einem Byte vor, die nach der ASCII-Tabelle als Buchstabe geschrieben wird, und warnte, dass 'ñ' nicht hineinpasst; die Lektion Kompilieren, Ausführen und Konfigurieren zeigte, dass "año" vier Bytes belegt, und richtete die Konsole ein, um es auszugeben. Diese Lektion erklärt, warum. ASCII ordnet 128 Zeichen eine Zahl zu, von 0 bis 127, die in sieben Bits passen: die Buchstaben des Englischen, die Ziffern, die Satzzeichen und einige Steuercodes. Nun enthält wirklicher Text das ñ, Akzente, Tremata, griechische Buchstaben, chinesische Ideogramme, mathematische Zeichen und Emojis, die zusammen Hunderttausende ausmachen. Daraus folgt, dass man erstens eine viel größere Tabelle braucht und zweitens eine Art, ihre Zahlen in Bytes zu schreiben.
Es empfiehlt sich, drei Ebenen zu unterscheiden. Die erste ist das abstrakte Zeichen: der Buchstabe „kleines ñ“, unabhängig davon, wie er gespeichert oder gezeichnet wird. Unicode ist der Standard, der jedem abstrakten Zeichen eine Zahl zuordnet, seinen Codepunkt, der als U+ mit mindestens vier hexadezimalen Ziffern geschrieben wird: das „ñ“ ist U+00F1 (241), das „A“ ist U+0041 (65, dieselbe Zahl wie in ASCII), das „€“ ist U+20AC (8364). Die Codepunkte reichen von 0 bis U+10FFFF, etwas mehr als eine Million. Die zweite Ebene ist die Kodierung: die Regel, die jeden Codepunkt in eine Folge von Bytes umwandelt. UTF-8 ist die Kodierung, die das Web, die heutigen Systeme und dieser Kurs verwenden. Die dritte Ebene ist die Darstellung: die Gestalt, die die Schriftart auf dem Bildschirm zeichnet und die sich von einer Schrift zur anderen ändern kann, ohne dass sich das Zeichen ändert.
Wenn dem so ist, ist ein Textdatum kein Text, solange seine Kodierung nicht bekannt ist: Die Bytes c3 b1 sind das „ñ“ in UTF-8, aber mit der Tabelle einer alten Konsole gelesen sind sie zwei Symbole ohne Bezug zu ihm, und das ist der Fehler, den die Lektion 1.4 zu diagnostizieren lehrte. Dieselbe Frage, vom Satz von Dokumenten aus gesehen, erscheint in der Lektion „Sprachen und Schriften“ aus dem Kurs LaTeX für das wissenschaftliche Schreiben.
Die Bytes sehen
Um die Bytes einer Zeichenkette zu sehen, genügt es, sie zu durchlaufen: Ein std::string und eine std::string_view sind Folgen von char, und die bereichsbasierte for-Schleife liefert ihre Bytes eines nach dem anderen. Um sie hexadezimal auszugeben, dient die Formatangabe {:02x} (zwei hexadezimale Ziffern, mit führender Null). Wie bei {:d} in der Lektion 2.4, und aufgrund derselben 2023 beschlossenen und von GCC 15 umgesetzten Korrektur des Standards, schreibt {:02x} ein char als vorzeichenloses Byte. Die Regel ist wichtig, weil char bei GCC auf x86-64 vorzeichenbehaftet ist: Das Byte c3, in int umgewandelt, ist die Zahl , die {:02x} als -3d schreiben würde.
#include <print>#include <string_view>// Bytes eines Textes.// Vorbedingung: keine.// Nachbedingung: gibt eine Zeile mit text, seiner Größe in Bytes und jedem Byte hexadezimal aus.void printBytes(std::string_view text){ std::print("{:<4}{}:", text, text.size()); for (const char c : text) { std::print(" {:02x}", c); } std::println("");}int main(){ printBytes("A"); printBytes("ñ"); printBytes("€"); printBytes("😀"); printBytes("año");}A 1: 41ñ 2: c3 b1€ 3: e2 82 ac😀 4: f0 9f 98 80año 4: 61 c3 b1 6fJede Zeile zeigt den Text, seine Größe und seine Bytes. Ein Zeichen jeder Länge: Das „A“ belegt ein Byte, das „ñ“ zwei, das „€“ drei und das Emoji vier. Das Wort „año“ belegt vier Bytes, 61, c3 b1 und 6f, und sein size() ist 4, nicht 3. Man beachte, dass das „A“ das Byte 41 ist, dasselbe wie in ASCII: UTF-8 schreibt die 128 Zeichen von ASCII genau wie ASCII.
Die Abbildung verfolgt die Kodierung des „ñ“ von oben nach unten: den Codepunkt, seine Bits, die Verteilung dieser Bits und die zwei entstehenden Bytes, mit hervorgehobenen Präfixbits.
Beweis
Das „ñ“ ist der Codepunkt
U+00F1, das heißt .Binär wird als
11110001geschrieben. Die Zahl ist größer als 127 und kleiner als 2048, sodass UTF-8 sie in zwei Bytes schreibt, die elf Bits tragen: Man füllt links mit Nullen bis auf elf auf,00011110001.Die elf Bits werden auf zwei Gruppen verteilt: die ersten fünf,
00011, und die letzten sechs,110001.Das erste Byte trägt das Präfix
110, das ein Zeichen aus zwei Bytes ankündigt, gefolgt von den fünf Bits der ersten Gruppe:11000011. Das zweite trägt das Präfix10, das ein Folgebyte kennzeichnet, gefolgt von den sechs übrigen Bits:10110001.Hexadezimal ist
1100 0011gleichc3und1011 0001gleichb1: die zwei Bytes, die das vorige Programm für das „ñ“ ausgab. Der Basiswechsel zwischen binär und hexadezimal, je vier Bits auf einmal, ist der aus der Lektion „Stellenwertsysteme“ aus dem Kurs Algebra und Geometrie I.
Inhalt wird geladen…
Abgeschlossen
Melde dich an, um deinen Fortschritt zu speichern