Wie funktioniert die UTF-8-Codierung mit variabler Breite?

110

Der Unicode-Standard enthält genügend Codepunkte, sodass Sie 4 Bytes benötigen, um alle zu speichern. Das macht die UTF-32-Codierung. Die UTF-8-Codierung drückt diese jedoch irgendwie in viel kleinere Räume, indem sie eine sogenannte "Codierung mit variabler Breite" verwendet.

Tatsächlich gelingt es ihm, die ersten 127 Zeichen von US-ASCII in nur einem Byte darzustellen, das genau wie echtes ASCII aussieht, sodass Sie viele ASCII-Texte so interpretieren können, als wäre es UTF-8, ohne etwas dagegen zu tun. Ordentlicher Trick. Wie funktioniert es?

Ich werde hier meine eigene Frage stellen und beantworten, weil ich nur ein bisschen gelesen habe, um es herauszufinden, und ich dachte, es könnte jemand anderem Zeit sparen. Außerdem kann mich vielleicht jemand korrigieren, wenn ich etwas falsch verstanden habe.

dsimard
quelle
8
Straight Unicode benötigt keine 32 Bit, um alle Codepunkte zu codieren. Sie haben einmal Anspruch auf so viele mögliche Codepunkte erhoben, aber nach dem Start von UTF-8 haben sie sich absichtlich auf 21 Bit beschränkt, sodass UTF-8 niemals 4 Bytes pro Zeichen überschreitet. Unicode benötigt derzeit nur 17 Bit, um alle möglichen Codepunkte aufzunehmen. Ohne diese Einschränkung hätte UTF-8 auf 6 Bytes pro Zeichen gehen können.
Warren Young
@ Warren: Meistens genau, aber Unicode ist ein 21-Bit-Code (U + 0000 bis U + 10FFFF).
Jonathan Leffler
2
@Warren: 4-Byte-limitiertes UTF-8 hätte bis zu U + 1FFFFF unterstützen können. Die Beschränkung auf U + 10FFFF wurde zugunsten von UTF-16 vorgenommen.
Dan04
@ dan04 Haben wir eine einfache Erklärung, wie es von UTF-16 auf U + 10FFFF beschränkt wird? Es wäre schön, mehr darüber zu wissen.
A-letubby
@ A-letubby: Da die UTF-16-Ersatzcodes so zugewiesen sind, dass 1024 Lead-Surrogate und 1024 Trail-Surrogate vorhanden sind (und nur paarweise verwendet werden können), werden 2 ^ 20 (ungefähr eine Million) zusätzliche Zeichen erstellt über das BMP hinaus verfügbar. Zusätzlich zu den im BMP verfügbaren 2 ^ 16 Zeichen werden 0x110000 Zeichen möglich.
Dan04

Antworten:

129

Jedes Byte beginnt mit einigen Bits, die angeben, ob es sich um einen Einzelbyte-Codepunkt, einen Mehrbyte-Codepunkt oder eine Fortsetzung eines Mehrbyte-Codepunkts handelt. So was:

0xxx xxxx    A single-byte US-ASCII code (from the first 127 characters)

Die Multi-Byte-Codepunkte beginnen jeweils mit ein paar Bits, die im Wesentlichen sagen: "Hey, Sie müssen auch das nächste Byte (oder zwei oder drei) lesen, um herauszufinden, was ich bin." Sie sind:

110x xxxx    One more byte follows
1110 xxxx    Two more bytes follow
1111 0xxx    Three more bytes follow

Schließlich sehen die Bytes, die diesen Startcodes folgen, alle so aus:

10xx xxxx    A continuation of one of the multi-byte characters

Da Sie anhand der ersten Bits erkennen können, welche Art von Byte Sie betrachten, verlieren Sie nicht die gesamte Sequenz, selbst wenn irgendwo etwas verstümmelt wird.

dsimard
quelle
14
Die Geschichte hat mehr zu bieten - denn die Codierung muss die kürzestmögliche Codierung für das Zeichen sein, was bedeutet, dass die Bytes 0xC0 und 0xC1 beispielsweise nicht in UTF-8 erscheinen können. und in der Tat kann 0xF5..0xFF auch nicht. Siehe die UTF-8-FAQ unter unicode.org/faq/utf_bom.html oder unicode.org/versions/Unicode5.2.0/ch03.pdf
Jonathan Leffler
2
Warum konnte es nicht nur ein Zeichen verwenden, um zu sagen next char is continuation? Wenn wir ein 3-Byte-Zeichen hätten, wäre es wie 1xxxxxxx 1xxxxxxx 0xxxxxxxfolgt : Es würde weniger Platz verschwendet.
9
@Soaku macht UTF-8 zu einem sogenannten "selbstsynchronisierenden" Code. Das heißt, wenn aufgrund von Fehlern Teile der Sequenz fehlen, ist es möglich, dies zu erkennen und alles zu verwerfen, was verstümmelt wurde. Wenn Sie ein Byte lesen, das mit 10xx beginnt und kein "Start" -Byte vorangestellt ist, können Sie es verwerfen, da es bedeutungslos ist. Wenn Sie ein System wie das beschriebene hatten und eines der ersten Bytes verloren geht, erhalten Sie möglicherweise ein anderes, gültiges Zeichen ohne Hinweis auf einen Fehler. Dies erleichtert auch das Auffinden des nächsten gültigen Zeichens und korrigiert fehlende "Fortsetzungs" -Bytes.
htmlcoderexe
9

RFC3629 - UTF-8, ein Transformationsformat von ISO 10646 ist hier die letzte Instanz und enthält alle Erklärungen.

Kurz gesagt, mehrere Bits in jedem Byte der UTF-8-codierten 1 bis 4-Byte-Sequenz, die ein einzelnes Zeichen darstellt, werden verwendet, um anzuzeigen, ob es sich um ein nachfolgendes Byte, ein führendes Byte handelt und wenn ja, wie viele Bytes folgen. Die restlichen Bits enthalten die Nutzlast.

Azheglov
quelle
1
Ummmm, dumm von mir, ich dachte, der Unicode-Standard sei die letzte Instanz von UTF-8
John Machin
6
Der Unicode-Standard definiert den Unicode selbst. Es werden keine verschiedenen heutigen und zukünftigen Methoden definiert, mit denen Unicode-Texte für eine Vielzahl von Zwecken (z. B. Speicherung und Transport) codiert werden können. UTF-8 ist eine dieser Methoden, und der obige Verweis bezieht sich auf das Dokument, das es definiert.
Azheglov
1
RFC3629, Seite 3, Abschnitt 3. besagt, dass "UTF-8 durch den Unicode-Standard definiert ist".
John Machin
Das Verfolgen von Links auf unicode.org führte mich zu Abschnitt 3.9 des Unicode-Standards und speziell zur Definition D92 (und auch tangential D86). Ich habe keine Ahnung, inwieweit dieser Link nützlich sein wird, wenn neue Versionen veröffentlicht werden, aber ich würde mir vorstellen, dass sie die Abschnitts- und Definitionskennungen über Versionen hinweg stabil halten möchten.
Tripleee
4

UTF-8 war ein weiteres System zum Speichern Ihrer Zeichenfolge von Unicode-Codepunkten, diesen magischen U + -Nummern, im Speicher mit 8-Bit-Bytes. In UTF-8 wird jeder Codepunkt von 0 bis 127 in einem einzelnen Byte gespeichert. Nur Codepunkte 128 und höher werden mit 2, 3, tatsächlich bis zu 6 Bytes gespeichert.

Auszug aus dem absoluten Minimum Jeder Softwareentwickler muss unbedingt über Unicode und Zeichensätze Bescheid wissen (keine Ausreden!)

Andrew
quelle
Das ist ein guter Artikel, aber es scheint, dass Joel in Bezug auf die maximale Länge der Sequenz falsch liegt. Auf der Wikipedia-Seite werden nur 1,4 Bytes pro Zeichen angezeigt.
Entspannen Sie sich
4
Wie ich oben sagte, als Unicode zum ersten Mal erstellt wurde, beanspruchte Unicode bis zu 32 Bit für Codepunkte, nicht weil sie es wirklich brauchten, sondern nur weil 32 Bit ein praktischer Wert sind und sie bereits über den Wert hinausgeblasen hatten vorherige Begrenzung auf 16-Bit-Zeichen. Nachdem sich UTF-8 als beliebt erwiesen hatte, wurde die maximale Anzahl von Codepunkten für immer auf 2 ^ 21 begrenzt. Dies ist der größte Wert, den Sie mit 4 Bytes des UTF-8-Schemas codieren können. Unicode enthält immer noch weniger als 2 ^ 17 Zeichen, sodass wir die Anzahl der Zeichen in Unicode mit diesem neuen Schema mehr als vervierfachen können.
Warren Young
Ok, aber nicht die Erklärung von OP.
Nishant
2
Dies beantwortet die Frage nicht.
Koray Tugay