UTF-8
UTF-8 (Abkürzung für 8-Bit UCS Transformation Format, wobei UCS wiederum Universal Coded Character Set abkürzt) ist die am weitesten verbreitete Kodierung für Unicode-Zeichen (Unicode und UCS sind praktisch identisch). Die Kodierung wurde im September 1992 von Ken Thompson und Rob Pike bei Arbeiten am Plan-9-Betriebssystem festgelegt. Sie wurde zunächst im Rahmen von X/Open als FSS-UTF bezeichnet (filesystem safe UTF in Abgrenzung zu UTF-1, das diese Eigenschaft nicht hat), in den Folgejahren erfolgte im Rahmen der Standardisierung die Umbenennung auf die heute übliche Bezeichnung UTF-8. ⓘ
UTF-8 ist in den ersten 128 Zeichen (Indizes 0–127) deckungsgleich mit ASCII und eignet sich mit in der Regel nur einem Byte Speicherbedarf für Zeichen vieler westlicher Sprachen, besonders für die Kodierung englischsprachiger Texte, die sich im Regelfall ohne Modifikation daher sogar mit nicht-UTF-8-fähigen Texteditoren ohne Beeinträchtigung bearbeiten lassen, was einen der Gründe für den Status als De-facto-Standard-Zeichenkodierung des Internet und damit verbundener Dokumenttypen darstellt. Im Juli 2022 verwendeten 97,7 % aller Websites UTF-8 und 98,8 % der Top 1000. ⓘ
In anderen Sprachen ist der Speicherbedarf in Byte pro Zeichen größer, wenn diese vom ASCII-Zeichensatz abweichen: Bereits die deutschen Umlaute erfordern zwei Byte, ebenso griechische oder kyrillische Zeichen. Zeichen fernöstlicher Sprachen und von Sprachen aus dem afrikanischen Raum belegen bis zu 4 Byte je Zeichen. Da die Verarbeitung von UTF-8 als Multibyte-Zeichenfolge wegen der notwendigen Analyse jedes Bytes im Vergleich zu Zeichenkodierungen mit fester Byteanzahl je Zeichen mehr Rechenaufwand und für bestimmte Sprachen auch mehr Speicherplatz erfordert, werden abhängig vom Einsatzszenario auch andere UTF-Kodierungen zur Abbildung von Unicode-Zeichensätzen verwendet. So führte Microsoft 1993 mit Windows NT 3.1 die Verwendung von UCS-2 ein, einer Zeichenkodierung, bei der jedes Zeichen fest zwei Bytes belegt. Da durch die spätere Weiterentwicklung von Unicode jedoch mit dieser Kodierung nicht mehr alle Zeichen darstellbar waren, erfolgte mit Windows 2000 ein neuerlicher Umstieg auf den kompatiblen Nachfolger UTF-16 Little Endian, womit man allerdings zugleich die Vorteile einer Kodierung mit fester Byteanzahl wieder verlor. ⓘ
UTF-8 ist eine Zeichenkodierung mit variabler Breite, die für die elektronische Kommunikation verwendet wird. Der vom Unicode-Standard definierte Name leitet sich von Unicode (oder Universal Coded Character Set) Transformation Format - 8-bit ab. ⓘ
UTF-8 ist die vorherrschende Kodierung für das World Wide Web (und Internet-Technologien), die ab 2022 98 % aller Webseiten und bis zu 100,0 % für einige Sprachen ausmacht. ⓘ
Benennung
Der offizielle Code der Internet Assigned Numbers Authority (IANA) für die Kodierung lautet "UTF-8". Alle Buchstaben werden großgeschrieben, und der Name wird mit Bindestrichen geschrieben. Diese Schreibweise wird in allen Dokumenten des Unicode-Konsortiums verwendet, die sich auf die Kodierung beziehen. ⓘ
Der Name "utf-8" kann jedoch von allen Standards verwendet werden, die mit der IANA-Liste konform sind (dazu gehören CSS, HTML, XML und HTTP-Header), da bei der Deklaration die Groß- und Kleinschreibung nicht berücksichtigt wird. ⓘ
Andere Varianten, z. B. solche, die den Bindestrich weglassen oder durch ein Leerzeichen ersetzen, d. h. "utf8" oder "UTF 8", werden von den geltenden Standards nicht als korrekt akzeptiert. Trotzdem können die meisten Webbrowser sie verstehen, so dass Standards, die die bestehende Praxis beschreiben sollen (z. B. HTML5), tatsächlich ihre Anerkennung verlangen können. ⓘ
Inoffiziell werden UTF-8-BOM und UTF-8-NOBOM manchmal für Textdateien verwendet, die eine Byte Order Mark (BOM) enthalten bzw. nicht enthalten. Insbesondere in Japan wird die UTF-8-Kodierung ohne BOM manchmal als "UTF-8N" bezeichnet. ⓘ
Windows XP und spätere Versionen, einschließlich aller unterstützten Windows-Versionen, haben den Zeichensatz 65001 als Synonym für UTF-8 (seit Windows 7 ist die Unterstützung für UTF-8 besser). Seit Windows 10 Version 1903 ist der Standard für Windows Notepad auf UTF-8 umgestellt. ⓘ
In PCL wird UTF-8 als Symbol-ID "18N" bezeichnet (PCL unterstützt 183 Zeichenkodierungen, die als Symbol-Sets bezeichnet werden und möglicherweise auf eine, 18N, reduziert werden können, die UTF-8 ist). ⓘ
Kodierung
Seit der Beschränkung des Unicode-Code-Raums auf 21-Bit-Werte im Jahr 2003 ist UTF-8 so definiert, dass Codepunkte in einem bis vier Bytes kodiert werden, je nach Anzahl der signifikanten Bits im numerischen Wert des Codepunkts. Die folgende Tabelle zeigt die Struktur der Kodierung. Die x-Zeichen werden durch die Bits des Codepunkts ersetzt. ⓘ
Erster Codepunkt | Letzter Codepunkt | Byte 1 | Byte 2 | Byte 3 | Byte 4 ⓘ |
---|---|---|---|---|---|
U+0000 | U+007F | 0xxxxxxx | |||
U+0080 | U+07FF | 110xxxxx | 10xxxxxx | ||
U+0800 | U+FFFF | 1110xxxx | 10xxxxxx | 10xxxxxx | |
U+10000 | U+10FFFF | 11110xxx | 10xxxxxx | 10xxxxxx | 10xxxxxx |
Die ersten 128 Zeichen (US-ASCII) benötigen ein Byte. Die nächsten 1.920 Zeichen benötigen zwei Bytes zur Kodierung, was den Rest fast aller Alphabete in lateinischer Schrift und auch IPA-Erweiterungen, griechische, kyrillische, koptische, armenische, hebräische, arabische, syrische, thailändische und N'Ko-Alphabete sowie kombinierte diakritische Zeichen umfasst. Drei Bytes werden für Zeichen im Rest der Basic Multilingual Plane benötigt, die praktisch alle gebräuchlichen Zeichen enthält, einschließlich der meisten chinesischen, japanischen und koreanischen Zeichen. Vier Bytes werden für Zeichen in den anderen Ebenen von Unicode benötigt, zu denen weniger verbreitete CJK-Zeichen, verschiedene historische Schriften, mathematische Symbole und Emoji (piktografische Symbole) gehören. ⓘ
Ein "Zeichen" kann mehr als 4 Bytes umfassen; z. B. benötigt ein Nationalflaggenzeichen 8 Bytes, da es "aus einem Paar von Unicode-Skalarwerten konstruiert" ist. ⓘ
Beispiele
Betrachten Sie die Kodierung des Euro-Zeichens, €:
- Der Unicode-Codepunkt für € ist U+20AC.
- Da dieser Codepunkt zwischen U+0800 und U+FFFF liegt, werden drei Bytes zur Kodierung benötigt.
- Hexadezimal 20AC ist binär 0010 0000 1010 1100. Die beiden führenden Nullen werden hinzugefügt, weil für eine Drei-Byte-Kodierung genau sechzehn Bits des Codepunkts benötigt werden.
- Da die Kodierung drei Bytes lang sein wird, beginnt das führende Byte mit drei 1en, dann folgt eine 0 (1110...)
- Die vier höchstwertigen Bits des Codepunkts werden in den verbleibenden niederwertigen vier Bits dieses Bytes gespeichert (11100010), so dass 12 Bits des Codepunkts noch zu kodieren sind (...0000 1010 1100).
- Alle Folgebytes enthalten genau sechs Bits des Codepunkts. Die nächsten sechs Bits des Codepunkts werden also in den niederwertigen sechs Bits des nächsten Bytes gespeichert, und 10 wird in den höherwertigen zwei Bits gespeichert, um es als Fortsetzungsbyte zu kennzeichnen (also 10000010).
- Schließlich werden die letzten sechs Bits des Codepunkts in den sechs niederwertigen Bits des letzten Bytes gespeichert, und wiederum wird 10 in den zwei höherwertigen Bits gespeichert (10101100). ⓘ
Die drei Bytes 11100010 10000010 10101100 lassen sich in hexadezimaler Schreibweise als E2 82 AC darstellen. ⓘ
Die folgende Tabelle fasst diese Konvertierung zusammen, sowie andere mit unterschiedlichen Längen in UTF-8. Die Farben zeigen an, wie die Bits des Codepunkts auf die UTF-8-Bytes verteilt werden. Zusätzliche Bits, die durch den UTF-8-Kodierungsprozess hinzugefügt wurden, sind in Schwarz dargestellt. ⓘ
Zeichen | Binärer Codepunkt | Binär UTF-8 | Hex UTF-8 | |
---|---|---|---|---|
$ | U+0024 | 010 0100 | 00100100 | 24 |
£ | U+00A3 | 0000 1010 0011 | 11000010 10100011 | C2 A3 |
ह | U+0939 | 0000 1001 0011 1001 | 11100000 10100100 10111001 | E0 A4 B9 |
€ | U+20AC | 0010 0000 1010 1100 | 11100010 10000010 10101100 | E2 82 AC |
한 | U+D55C | 1101 0101 0101 1100 | 11101101 10010101 10011100 | ED 95 9C |
𐍈 | U+10348 | 0 0001 0000 0011 0100 1000 | 11110000 10010000 10001101 10001000 | F0 90 8D 88 |
Das letzte Beispiel liegt außerhalb des ursprünglich in Unicode (unter Version 2.0) enthaltenen Codebereiches (16 Bit), der in der aktuellen Unicode-Version als BMP-Bereich (Ebene 0) enthalten ist. Da derzeit viele Schriftarten diese neuen Unicode-Bereiche noch nicht enthalten, können die dort enthaltenen Zeichen auf vielen Plattformen nicht korrekt dargestellt werden. Stattdessen wird ein Ersatzzeichen dargestellt, welches als Platzhalter dient. ⓘ
Oktal
Da UTF-8 sechs Bits pro Byte verwendet, um die kodierten Zeichen darzustellen, kann die oktale Notation (die 3-Bit-Gruppen verwendet) beim Vergleich von UTF-8-Sequenzen untereinander und bei der manuellen Konvertierung helfen. ⓘ
Erster Codepunkt | Letzter Codepunkt | Code-Punkt | Byte 1 | Byte 2 | Byte 3 | Byte 4 ⓘ |
---|---|---|---|---|---|---|
000 | 0177 | xxx | xxx | |||
0200 | 03777 | xxyy | 3xx | 2yy | ||
04000 | 077777 | xyyzz | 34x | 2yy | 2zz | |
0100000 | 0177777 | 1xyyzz | 35x | 2yy | 2zz | |
0200000 | 04177777 | xyyzzww | 36x | 2yy | 2zz | 2ww |
Bei der Oktalschreibweise bleiben die beliebigen Oktalziffern, die in der Tabelle mit x, y, z oder w gekennzeichnet sind, bei der Konvertierung nach oder von UTF-8 unverändert.
- Beispiel: Á = U+00C1 = 0301 (in Oktal) wird in UTF-8 als 303 201 kodiert (C3 81 in Hex).
- Beispiel: € = U+20AC = 020254 wird kodiert als 342 202 254 in UTF-8 (E2 82 AC in hex). ⓘ
Codepage-Layout
Die folgende Tabelle fasst die Verwendung von UTF-8-Codeeinheiten (einzelne Bytes oder Oktette) in einem Codepage-Format zusammen. Die obere Hälfte ist für Bytes, die nur in Einzelbyte-Codes verwendet werden, so dass sie wie eine normale Codepage aussieht; die untere Hälfte ist für Fortsetzungsbytes und führende Bytes und wird in der Legende weiter unten erläutert. ⓘ
UTF-8 ⓘ | ||||||||||||||||
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | |
0x | NUL | SOH | STX | ETX | EOT | ENQ | ACK | BEL | BS | HT | LF | VT | FF | CR | SO | SI |
1x | DLE | DC1 | DC2 | DC3 | DC4 | NAK | SYN | ETB | CAN | EM | SUB | ESC | FS | GS | RS | US |
2x | SP | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / |
3x | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? |
4x | @ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O |
5x | P | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ^ | _ |
6x | ` | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o |
7x | p | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ | DEL |
8x | • | • | • | • | • | • | • | • | • | • | • | • | • | • | • | • |
9x | • | • | • | • | • | • | • | • | • | • | • | • | • | • | • | • |
Ax | • | • | • | • | • | • | • | • | • | • | • | • | • | • | • | • |
Bx | • | • | • | • | • | • | • | • | • | • | • | • | • | • | • | • |
Cx | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
Dx | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
Ex | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |
Fx | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 5 | 5 | 5 | 5 | 6 | 6 |
Überlange Kodierungen
Prinzipiell wäre es möglich, die Anzahl der Bytes in einer Kodierung durch Auffüllen des Codepunkts mit führenden 0s aufzublähen. Um das Euro-Zeichen € aus dem obigen Beispiel in vier statt in drei Bytes zu kodieren, könnte es mit führenden 0s aufgefüllt werden, bis es 21 Bit lang ist - 000 000010 000010 101100, und kodiert als 11110000 10000010 10000010 10101100 (oder F0 82 82 AC in Hexadezimal). Dies nennt man eine überlange Kodierung. ⓘ
Die Norm legt fest, dass die korrekte Kodierung eines Codepunkts nur die Mindestanzahl von Bytes verwendet, die erforderlich ist, um die signifikanten Bits des Codepunkts zu speichern. Längere Kodierungen werden als overlong bezeichnet und sind keine gültigen UTF-8-Darstellungen des Codepunkts. Diese Regel sorgt für eine Eins-zu-eins-Entsprechung zwischen Codepunkten und ihren gültigen Kodierungen, so dass es für jeden Codepunkt eine eindeutige gültige Kodierung gibt. Dadurch wird sichergestellt, dass String-Vergleiche und -Suchen wohldefiniert sind. ⓘ
Ungültige Sequenzen und Fehlerbehandlung
Nicht alle Bytefolgen sind gültige UTF-8. Ein UTF-8-Decoder sollte darauf vorbereitet sein:
- ungültige Bytes
- ein unerwartetes Fortsetzungsbyte
- ein Nicht-Fortsetzungsbyte vor dem Ende des Zeichens
- das Ende der Zeichenkette vor dem Ende des Zeichens (was bei der einfachen Abtrennung von Zeichenketten vorkommen kann)
- eine überlange Kodierung
- eine Sequenz, die zu einem ungültigen Codepunkt dekodiert wird ⓘ
Viele der ersten UTF-8-Dekoder würden diese dekodieren, wobei sie falsche Bits ignorieren und überlange Ergebnisse akzeptieren würden. Sorgfältig erstelltes ungültiges UTF-8 konnte dazu führen, dass sie ASCII-Zeichen wie NUL, Schrägstrich oder Anführungszeichen entweder übersprangen oder erzeugten. Ungültiges UTF-8 wurde verwendet, um Sicherheitsvalidierungen in bekannten Produkten wie dem IIS-Webserver von Microsoft und dem Tomcat-Servlet-Container von Apache zu umgehen. In RFC 3629 heißt es: "Implementierungen des Dekodierungsalgorithmus MÜSSEN sich gegen die Dekodierung ungültiger Sequenzen schützen." Der Unicode-Standard verlangt von Dekodierern, dass sie "...jede ungültige Code-Unit-Sequenz als Fehlerzustand behandeln. Dies garantiert, dass er eine ungültige Code-Unit-Sequenz weder interpretieren noch ausgeben wird. ⓘ
Seit RFC 3629 (November 2003) sind die von UTF-16 verwendeten hohen und niedrigen Surrogathälften (U+D800 bis U+DFFF) und die von UTF-16 nicht kodierbaren Codepunkte (die nach U+10FFFF) keine legalen Unicode-Werte, und ihre UTF-8-Kodierung muss als ungültige Bytefolge behandelt werden. Wenn ungepaarte Surrogathälften nicht dekodiert werden, ist es unmöglich, ungültiges UTF-16 (wie Windows-Dateinamen oder UTF-16, das zwischen den Surrogaten aufgeteilt wurde) als UTF-8 zu speichern, während dies bei WTF-8 möglich ist. ⓘ
Einige Implementierungen von Decodern lösen bei Fehlern Ausnahmen aus. Dies hat den Nachteil, dass es ansonsten harmlose Fehler (wie den Fehler "no such file") in eine Dienstverweigerung verwandeln kann. Frühe Versionen von Python 3.0 haben sich beispielsweise sofort beendet, wenn die Befehlszeile oder Umgebungsvariablen ungültiges UTF-8 enthielten. Eine alternative Praxis ist es, Fehler durch ein Ersatzzeichen zu ersetzen. Seit Unicode 6 (Oktober 2010) empfiehlt der Standard (Kapitel 3) eine "beste Praxis", bei der der Fehler endet, sobald ein unzulässiges Byte angetroffen wird. In diesen Decodern ist E1,A0,C0 zwei Fehler (2 Bytes im ersten). Das bedeutet, dass ein Fehler nicht länger als drei Bytes ist und nie den Anfang eines gültigen Zeichens enthält, und dass es 21.952 verschiedene mögliche Fehler gibt. Die Norm empfiehlt außerdem, jeden Fehler durch das Ersatzzeichen "�" (U+FFFD) zu ersetzen. ⓘ
Byte-Order-Markierung
Wenn das UTF-16 Unicode Byte Order Mark (BOM, U+FEFF) Zeichen am Anfang einer UTF-8 Datei steht, sind die ersten drei Bytes 0xEF, 0xBB, 0xBF. ⓘ
Der Unicode-Standard schreibt die Verwendung des BOM-Zeichens für UTF-8 weder vor noch empfiehlt er sie, warnt aber davor, dass es am Anfang einer Datei, die aus einer anderen Kodierung transkodiert wurde, vorkommen kann. Während ASCII-Text, der mit UTF-8 kodiert wurde, abwärtskompatibel zu ASCII ist, trifft dies nicht zu, wenn die Empfehlungen des Unicode-Standards ignoriert werden und ein BOM hinzugefügt wird. Ein BOM kann Software verwirren, die nicht darauf vorbereitet ist, aber ansonsten UTF-8 akzeptieren kann, z. B. Programmiersprachen, die Nicht-ASCII-Bytes in String-Literalen, aber nicht am Anfang der Datei zulassen. Dennoch gab und gibt es Software, die beim Schreiben von UTF-8 immer ein BOM einfügt und sich weigert, UTF-8 korrekt zu interpretieren, wenn nicht das erste Zeichen ein BOM ist (oder die Datei nur ASCII enthält). ⓘ
Annahme
Viele Standards unterstützen nur UTF-8, z. B. erfordert der offene JSON-Austausch dies (ohne Byte Order Mark (BOM)). UTF-8 ist auch die Empfehlung der WHATWG für HTML- und DOM-Spezifikationen, und das Internet Mail Consortium empfiehlt, dass alle E-Mail-Programme in der Lage sein sollten, E-Mails in UTF-8 anzuzeigen und zu erstellen. Das World Wide Web Consortium empfiehlt UTF-8 als Standardkodierung in XML und HTML (und nicht nur die Verwendung von UTF-8, sondern auch die Deklaration in den Metadaten), "selbst wenn alle Zeichen im ASCII-Bereich liegen ... Die Verwendung von Nicht-UTF-8-Kodierungen kann zu unerwarteten Ergebnissen führen". ⓘ
Viele Software bietet die Möglichkeit, UTF-8 zu lesen und zu schreiben, allerdings muss der Benutzer dazu oft Optionen aus den normalen Einstellungen ändern und kann ein BOM (Byte Order Mark) als erstes Zeichen zum Lesen der Datei benötigen. Beispiele hierfür sind Microsoft Word und Microsoft Excel. Die meisten Datenbanken unterstützen UTF-8 (manchmal die einzige Option wie bei einigen Dateiformaten), darunter auch Microsofts SQL Server 2019, was zu einer Geschwindigkeitssteigerung von 35 % und einer "Reduzierung der Speicheranforderungen um fast 50 %" führt. ⓘ
UTF-8 ist seit 2008 die häufigste Kodierung im World Wide Web. Im Juli 2022 waren im Durchschnitt 97,7 % aller Webseiten in UTF-8 kodiert (und 989 der 1.000 bestplatzierten Webseiten). UTF-8 umfasst ASCII als Untermenge; fast keine Website gibt an, nur ASCII zu verwenden. Mehr als ein Drittel der untersuchten Sprachen verwenden zu 100,0 % UTF-8. ⓘ
Bei lokalen Textdateien ist die Verwendung von UTF-8 geringer, und viele alte Ein-Byte-Kodierungen (und CJK-Mehr-Byte-Kodierungen) werden weiterhin verwendet. Die Hauptursache dafür sind Editoren, die UTF-8 nur dann anzeigen oder schreiben, wenn das erste Zeichen in einer Datei ein Byte Order Mark (BOM) ist, was es für andere Software unmöglich macht, UTF-8 zu verwenden, ohne umgeschrieben zu werden, um das Byte Order Mark bei der Eingabe zu ignorieren und bei der Ausgabe hinzuzufügen. Es hat einige Verbesserungen gegeben, Notepad unter Windows 10 schreibt standardmäßig UTF-8 ohne BOM, und einige Systemdateien unter Windows 11 erfordern UTF-8, und fast alle Dateien unter macOS und Linux müssen UTF-8 (ohne BOM) sein. Java 18 liest und schreibt Dateien standardmäßig in UTF-8, und in älteren Versionen tat dies nur die NIO-API. Viele andere Programmiersprachen verwenden standardmäßig UTF-8 für E/A oder planen die Umstellung auf UTF-8, wie z. B. Python, das bereits Änderungen vorgenommen hat, um Programmierer bei der Vorbereitung auf die Umstellung auf UTF-8 zu unterstützen, [da es] die De-facto-Standard-Textkodierung geworden ist". ⓘ
Intern in der Software ist die Verwendung von UTF-16 geringer, insbesondere unter Windows, aber auch bei JavaScript, Python, Qt und vielen anderen plattformübergreifenden Softwarebibliotheken. Dies ist in erster Linie auf die Kompatibilität mit der Windows-API zurückzuführen (obwohl auch die Überzeugung, dass die direkte Indizierung von BMP die Geschwindigkeit erhöht, ein Faktor war). Neuere Software verwendet (fast) ausschließlich UTF-8: Das Standard-String-Primitiv, das in Go, Julia, Rust, Swift 5 und PyPy verwendet wird, ist UTF-8, eine künftige Version von Python beabsichtigt, Strings als UTF-8 zu speichern, und moderne Versionen von Microsoft Visual Studio verwenden intern UTF-8 (erfordern jedoch immer noch einen Befehlszeilenschalter, um UTF-8 zu lesen oder zu schreiben). UTF-8 ist die einzige Textkodierung, die vom C++-Standard unterstützt wird (Stand: C++20). Ab Mai 2019 hat Microsoft seinen Kurs, nur UTF-16 für die Windows-API zu unterstützen, umgekehrt und die Möglichkeit geschaffen, UTF-8 als "Codepage" für die Multi-Byte-API festzulegen (zuvor war dies nicht möglich), und nun empfiehlt Microsoft Programmierern die Verwendung von UTF-8. ⓘ
Geschichte
Die Internationale Organisation für Normung (ISO) machte sich 1989 daran, einen universellen Multi-Byte-Zeichensatz zusammenzustellen. Der Entwurf der Norm ISO 10646 enthielt einen nicht vorgeschriebenen Anhang namens UTF-1, der eine Bytestrom-Kodierung der 32-Bit-Codepunkte vorsah. Diese Kodierung war unter anderem aus Leistungsgründen nicht zufriedenstellend, und das größte Problem war wahrscheinlich, dass es keine klare Trennung zwischen ASCII und Nicht-ASCII gab: Neue UTF-1-Tools wären abwärtskompatibel mit ASCII-kodiertem Text, aber UTF-1-kodierter Text könnte bestehenden Code, der ASCII (oder erweitertes ASCII) erwartet, verwirren, weil er Fortsetzungsbytes im Bereich 0x21-0x7E enthalten könnte, die in ASCII etwas anderes bedeuten, z. B., 0x2F für '/', das Unix-Pfadverzeichnistrennzeichen, und dieses Beispiel spiegelt sich im Namen und Einleitungstext des Ersatzes wider. Die folgende Tabelle wurde aus einer textlichen Beschreibung im Anhang abgeleitet. ⓘ
Nummer von Bytes |
Erste Codepunkt |
Letzter Codepunkt |
Byte 1 | Byte 2 | Byte 3 | Byte 4 | Byte 5 |
---|---|---|---|---|---|---|---|
1 | U+0000 | U+009F | 00-9F | ||||
2 | U+00A0 | U+00FF | A0 | A0-FF | |||
2 | U+0100 | U+4015 | A1-F5 | 21-7E, A0-FF | |||
3 | U+4016 | U+38E2D | F6-FB | 21-7E, A0-FF | 21-7E, A0-FF | ||
5 | U+38E2E | U+7FFFFFFF | FC-FF | 21-7E, A0-FF | 21-7E, A0-FF | 21-7E, A0-FF | 21-7E, A0-FF |
Im Juli 1992 war das X/Open-Komitee XoJIG auf der Suche nach einer besseren Kodierung. Dave Prosser von den Unix System Laboratories unterbreitete einen Vorschlag für eine Kodierung mit schnelleren Implementierungseigenschaften und der Verbesserung, dass 7-Bit-ASCII-Zeichen nur sich selbst darstellen würden; alle Multi-Byte-Sequenzen würden nur Bytes enthalten, bei denen das hohe Bit gesetzt ist. Der Name File System Safe UCS Transformation Format (FSS-UTF) und der größte Teil des Textes dieses Vorschlags wurden später in die endgültige Spezifikation übernommen. ⓘ
FSS-UTF
Nummer von Bytes |
Erste Codepunkt |
Letzter Codepunkt |
Byte 1 | Byte 2 | Byte 3 | Byte 4 | Byte 5 |
---|---|---|---|---|---|---|---|
1 | U+0000 | U+007F | 0xxxxxxx | ||||
2 | U+0080 | U+207F | 10xxxxxx | 1xxxxxxx | |||
3 | U+2080 | U+8207F | 110xxxxx | 1xxxxxxx | 1xxxxxxx | ||
4 | U+82080 | U+208207F | 1110xxxx | 1xxxxxxx | 1xxxxxxx | 1xxxxxxx | |
5 | U+2082080 | U+7FFFFFFF | 11110xxx | 1xxxxxxx | 1xxxxxxx | 1xxxxxxx | 1xxxxxxx |
Im August 1992 wurde dieser Vorschlag von einem Vertreter von IBM X/Open an interessierte Kreise weitergeleitet. Durch eine Änderung von Ken Thompson von der Plan 9-Betriebssystemgruppe bei Bell Labs wurde er selbstsynchronisierend, so dass ein Lesegerät an beliebiger Stelle ansetzen und Zeichengrenzen sofort erkennen konnte, was allerdings den Preis hatte, dass er etwas weniger bit-effizient war als der vorherige Vorschlag. Der zusätzliche Verlust an Kompaktheit ist relativ unbedeutend, aber die Leser müssen nun auf ungültige Kodierungen achten, um Zuverlässigkeits- und insbesondere Sicherheitsprobleme zu vermeiden. Thompsons Entwurf wurde am 2. September 1992 auf einem Tischset in einem Diner in New Jersey mit Rob Pike skizziert. In den folgenden Tagen implementierten Pike und Thompson es und aktualisierten Plan 9, um es durchgängig zu verwenden, und teilten dann ihren Erfolg X/Open mit, das es als Spezifikation für FSS-UTF akzeptierte. ⓘ
Nummer von Bytes |
Erste Codepunkt |
Letzter Codepunkt |
Byte 1 | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6 |
---|---|---|---|---|---|---|---|---|
1 | U+0000 | U+007F | 0xxxxxxx | |||||
2 | U+0080 | U+07FF | 110xxxxx | 10xxxxxx | ||||
3 | U+0800 | U+FFFF | 1110xxxx | 10xxxxxx | 10xxxxxx | |||
4 | U+10000 | U+1FFFFF | 11110xxx | 10xxxxxx | 10xxxxxx | 10xxxxxx | ||
5 | U+200000 | U+3FFFFFF | 111110xx | 10xxxxxx | 10xxxxxx | 10xxxxxx | 10xxxxxx | |
6 | U+4000000 | U+7FFFFFFF | 1111110x | 10xxxxxx | 10xxxxxx | 10xxxxxx | 10xxxxxx | 10xxxxxx |
UTF-8 wurde erstmals offiziell auf der USENIX-Konferenz in San Diego vom 25. bis 29. Januar 1993 vorgestellt. Die Internet Engineering Task Force hat UTF-8 in ihrer Policy on Character Sets and Languages in RFC 2277 (BCP 18) für die künftige Arbeit an Internetstandards übernommen und damit Single Byte Character Sets wie Latin-1 in älteren RFCs ersetzt. ⓘ
Im November 2003 wurde UTF-8 durch RFC 3629 eingeschränkt, um den Einschränkungen der UTF-16-Zeichenkodierung zu entsprechen: Durch das explizite Verbot von Codepunkten, die den hohen und niedrigen Surrogatzeichen entsprechen, wurden mehr als 3 % der 3-Byte-Sequenzen entfernt, und durch die Beendigung bei U+10FFFF wurden mehr als 48 % der 4-Byte-Sequenzen und alle 5- und 6-Byte-Sequenzen entfernt. ⓘ
Normen
Es gibt mehrere aktuelle Definitionen von UTF-8 in verschiedenen Standarddokumenten:
- RFC 3629 / STD 63 (2003), das UTF-8 als Standard-Internetprotokollelement festlegt
- RFC 5198 definiert UTF-8 NFC für Network Interchange (2008)
- ISO/IEC 10646:2014 §9.1 (2014)
- Der Unicode-Standard, Version 11.0 (2018) ⓘ
Sie ersetzen die Definitionen, die in den folgenden veralteten Werken enthalten sind:
- The Unicode Standard, Version 2.0, Appendix A (1996)
- ISO/IEC 10646-1:1993 Änderung 2 / Anhang R (1996)
- RFC 2044 (1996)
- RFC 2279 (1998)
- The Unicode Standard, Version 3.0, §2.3 (2000) plus Corrigendum #1: UTF-8 Shortest Form (2000)
- Unicode Standard Anhang #27: Unicode 3.1 (2001)
- Der Unicode-Standard, Version 5.0 (2006)
- Der Unicode-Standard, Version 6.0 (2010) ⓘ
Sie sind in ihrer allgemeinen Mechanik alle gleich, wobei die Hauptunterschiede in Fragen wie dem zulässigen Bereich von Codepunktwerten und dem sicheren Umgang mit ungültigen Eingaben bestehen. ⓘ
Vergleich mit anderen Kodierungen
Einige der wichtigsten Merkmale dieser Kodierung sind die folgenden
- Abwärtskompatibilität: Die Abwärtskompatibilität mit ASCII und der enormen Menge an Software, die für die Verarbeitung von ASCII-kodiertem Text entwickelt wurde, war die Hauptantriebskraft für die Entwicklung von UTF-8. In UTF-8 werden einzelne Bytes mit Werten im Bereich von 0 bis 127 direkt auf Unicode-Codepunkte im ASCII-Bereich abgebildet. Einzelne Bytes in diesem Bereich stellen Zeichen dar, wie sie es auch in ASCII tun. Außerdem kommen 7-Bit-Bytes (Bytes, bei denen das höchstwertige Bit 0 ist) nie in einer Multi-Byte-Sequenz vor, und keine gültige Multi-Byte-Sequenz lässt sich in einen ASCII-Codepunkt decodieren. Eine Folge von 7-Bit-Bytes ist sowohl als ASCII als auch als UTF-8 gültig und stellt in beiden Fällen dieselbe Zeichenfolge dar. Daher repräsentieren die 7-Bit-Bytes in einem UTF-8-Datenstrom alle und nur die ASCII-Zeichen in diesem Datenstrom. Daher funktionieren viele Textverarbeitungsprogramme, Parser, Protokolle, Dateiformate, Textanzeigeprogramme usw., die ASCII-Zeichen für Formatierungs- und Steuerungszwecke verwenden, weiterhin wie vorgesehen, indem sie den UTF-8-Byte-Strom als eine Folge von Einzelbyte-Zeichen behandeln, ohne die Multibyte-Sequenzen zu dekodieren. ASCII-Zeichen, auf die sich die Verarbeitung bezieht, wie Satzzeichen, Leerzeichen und Steuerzeichen, werden niemals als Multi-Byte-Sequenzen kodiert. Daher ist es für solche Prozessoren sicher, die Multi-Byte-Sequenzen einfach zu ignorieren oder durchzulassen, ohne sie zu dekodieren. ASCII-Whitespace kann beispielsweise verwendet werden, um einen UTF-8-Datenstrom in Wörter zu zerlegen; ASCII-Zeilenvorschübe können verwendet werden, um einen UTF-8-Datenstrom in Zeilen aufzuteilen; und ASCII-NUL-Zeichen können verwendet werden, um UTF-8-kodierte Daten in null-terminierte Strings aufzuteilen. Auch viele Formatstrings, die von Bibliotheksfunktionen wie "printf" verwendet werden, verarbeiten UTF-8-kodierte Eingabeargumente korrekt.
- Fallback und automatische Erkennung: Nur eine kleine Teilmenge möglicher Byte-Zeichenketten ist eine gültige UTF-8-Zeichenkette: Die Bytes C0, C1 und F5 bis FF können nicht vorkommen, und Bytes mit gesetztem High-Bit müssen paarweise vorkommen, sowie weitere Anforderungen. Es ist äußerst unwahrscheinlich, dass ein lesbarer Text in einem erweiterten ASCII-Format als UTF-8 gültig ist. Ein Teil der Popularität von UTF-8 ist darauf zurückzuführen, dass es auch für diese eine Form der Abwärtskompatibilität bietet. Ein UTF-8-Prozessor, der fälschlicherweise erweitertes ASCII als Eingabe erhält, kann dies daher mit sehr hoher Zuverlässigkeit "automatisch erkennen". Fallback-Fehler werden falsch-negativ sein, und diese werden selten sein. Außerdem sind die Folgen eines fehlerhaften Fallbacks in vielen Anwendungen, z. B. bei der Textanzeige, normalerweise gering. Ein UTF-8-Datenstrom kann einfach nur Fehler enthalten, die dazu führen, dass das automatische Erkennungsschema falsch-positive Ergebnisse liefert; aber die automatische Erkennung ist in den meisten Fällen erfolgreich, insbesondere bei längeren Texten, und wird häufig verwendet. Die automatische Erkennung ist jedoch in den meisten Fällen erfolgreich, vor allem bei längeren Texten, und wird daher häufig verwendet. Außerdem werden 8-Bit-Bytes nur dann durch den entsprechenden Code-Point für eine ältere Kodierung ersetzt, wenn Fehler in UTF-8 erkannt werden, so dass eine Wiederherstellung auch dann möglich ist, wenn UTF-8 und ältere Kodierung in derselben Datei verkettet sind.
- Präfix-Code: Das erste Byte gibt die Anzahl der Bytes in der Sequenz an. Beim Lesen aus einem Datenstrom kann jede einzelne vollständig empfangene Sequenz sofort dekodiert werden, ohne dass zunächst das erste Byte einer nächsten Sequenz oder ein Hinweis auf das Ende des Datenstroms abgewartet werden muss. Die Länge von Multi-Byte-Sequenzen kann von Menschen leicht bestimmt werden, da sie einfach die Anzahl der höherwertigen 1en im führenden Byte ist. Ein falsches Zeichen wird nicht dekodiert, wenn ein Stream in der Mitte der Sequenz endet.
- Selbstsynchronisierung: Die führenden Bytes und die Fortsetzungsbytes teilen sich keine Werte (Fortsetzungsbytes beginnen mit den Bits 10, während einzelne Bytes mit 0 und längere führende Bytes mit 11 beginnen). Dies bedeutet, dass eine Suche nicht versehentlich die Sequenz für ein Zeichen findet, das in der Mitte eines anderen Zeichens beginnt. Es bedeutet auch, dass der Anfang eines Zeichens von einer zufälligen Position aus gefunden werden kann, indem man maximal 3 Bytes zurückgeht, um das führende Byte zu finden. Ein falsches Zeichen wird nicht dekodiert, wenn ein Stream in der Mitte der Sequenz beginnt, und eine kürzere Sequenz wird nie innerhalb einer längeren erscheinen.
- Sortierreihenfolge: Die gewählten Werte der führenden Bytes bedeuten, dass eine Liste von UTF-8-Zeichenfolgen in Codepoint-Reihenfolge sortiert werden kann, indem die entsprechenden Bytefolgen sortiert werden. ⓘ
Einzelnes Byte
- UTF-8 kann jedes beliebige Unicode-Zeichen kodieren, so dass es nicht notwendig ist, eine "Codepage" zu ermitteln und festzulegen oder anderweitig anzugeben, welcher Zeichensatz verwendet wird, und die Ausgabe in mehreren Skripten gleichzeitig zu ermöglichen. Für viele Skripte wurde mehr als eine Ein-Byte-Kodierung verwendet, so dass selbst die Kenntnis des Skripts nicht ausreichte, um es korrekt anzuzeigen.
- Die Bytes 0xFE und 0xFF tauchen nicht auf, so dass ein gültiger UTF-8-Stream niemals mit der UTF-16-Byte-Order-Marke übereinstimmt und daher nicht mit ihr verwechselt werden kann. Durch das Fehlen von 0xFF (0377) entfällt auch die Notwendigkeit, dieses Byte in Telnet (und FTP-Kontrollverbindungen) zu umgehen.
- UTF-8-kodierter Text ist größer als spezialisierte Einzelbyte-Kodierungen, mit Ausnahme von einfachen ASCII-Zeichen. Bei Skripten, die 8-Bit-Zeichensätze mit nicht-lateinischen Zeichen in der oberen Hälfte verwenden (wie die meisten Codeseiten des kyrillischen und griechischen Alphabets), sind die Zeichen in UTF-8 doppelt so groß. Bei einigen Schriften wie Thai und Devanagari (das von verschiedenen südasiatischen Sprachen verwendet wird) verdreifacht sich die Größe der Zeichen. Es gibt sogar Beispiele dafür, dass ein einzelnes Byte in Unicode zu einem zusammengesetzten Zeichen wird und somit in UTF-8 sechsmal größer ist. Dies hat in Indien und anderen Ländern zu Beanstandungen geführt.
- In UTF-8 (oder jeder anderen Multi-Byte-Kodierung) ist es möglich, eine Zeichenkette in der Mitte eines Zeichens zu teilen oder abzuschneiden. Wenn die beiden Teile später nicht wieder zusammengefügt werden, bevor sie als Zeichen interpretiert werden, kann dies zu einer ungültigen Sequenz sowohl am Ende des vorherigen Abschnitts als auch am Anfang des nächsten Abschnitts führen, und einige Decoder behalten diese Bytes nicht bei, was zu Datenverlust führt. Da UTF-8 selbstsynchronisierend ist, wird dadurch jedoch nie ein anderes gültiges Zeichen eingeführt, und es ist auch recht einfach, den Abbruchpunkt nach hinten an den Anfang eines Zeichens zu verschieben.
- Wenn die Codepunkte alle die gleiche Größe haben, ist die Messung einer festen Anzahl von ihnen einfach. Aufgrund der Dokumentation aus der ASCII-Ära, in der "Zeichen" als Synonym für "Byte" verwendet wird, wird dies oft als wichtig angesehen. Durch die Messung von Zeichenkettenpositionen anhand von Bytes anstelle von "Zeichen" können die meisten Algorithmen jedoch einfach und effizient an UTF-8 angepasst werden. Die Suche nach einer Zeichenkette innerhalb einer langen Zeichenkette kann z. B. byteweise erfolgen; die Eigenschaft der Selbstsynchronisierung verhindert falsch positive Ergebnisse. ⓘ
Andere Multi-Byte
- UTF-8 kann jedes Unicode-Zeichen kodieren. Dateien in verschiedenen Schriftarten können korrekt angezeigt werden, ohne dass die richtige Codepage oder Schriftart gewählt werden muss. So können z. B. Chinesisch und Arabisch in ein und derselben Datei geschrieben werden, ohne dass spezielles Markup oder manuelle Einstellungen zur Festlegung einer Kodierung erforderlich sind.
- UTF-8 ist selbstsynchronisierend: Zeichengrenzen lassen sich leicht erkennen, indem in beiden Richtungen nach wohldefinierten Bitmustern gesucht wird. Wenn Bytes aufgrund eines Fehlers oder einer Beschädigung verloren gehen, kann man immer das nächste gültige Zeichen finden und die Verarbeitung fortsetzen. Wenn eine Zeichenkette gekürzt werden muss, damit sie in ein bestimmtes Feld passt, kann das vorherige gültige Zeichen leicht gefunden werden. Viele Multi-Byte-Kodierungen wie Shift JIS sind viel schwieriger zu resynchronisieren. Dies bedeutet auch, dass mit UTF-8 byteorientierte Algorithmen für die Zeichenkettensuche verwendet werden können (da ein Zeichen einem "Wort" entspricht, das aus so vielen Bytes besteht). Optimierte Versionen der Bytesuche können aufgrund von Hardwareunterstützung und Nachschlagetabellen, die nur 256 Einträge haben, viel schneller sein. Die Selbstsynchronisierung erfordert jedoch, dass in jedem Byte Bits für diese Markierungen reserviert werden, was die Größe erhöht.
- Effiziente Kodierung durch einfache bitweise Operationen. UTF-8 erfordert keine langsameren mathematischen Operationen wie Multiplikation oder Division (im Gegensatz zu Shift JIS, GB 2312 und anderen Kodierungen).
- UTF-8 benötigt mehr Platz als eine Multi-Byte-Kodierung, die für eine bestimmte Schrift entwickelt wurde. Ostasiatische Legacy-Kodierungen verwenden im Allgemeinen zwei Bytes pro Zeichen, benötigen aber in UTF-8 drei Bytes pro Zeichen. ⓘ
UTF-16
- Byte-Kodierungen und UTF-8 werden in Programmen durch Byte-Arrays dargestellt, und oft muss an einer Funktion nichts geändert werden, wenn Quellcode von einer Byte-Kodierung nach UTF-8 konvertiert wird. UTF-16 wird durch 16-Bit-Wort-Arrays dargestellt, und die Konvertierung zu UTF-16 unter Beibehaltung der Kompatibilität mit bestehenden ASCII-basierten Programmen (wie es bei Windows der Fall war) erfordert die Duplizierung aller APIs und Datenstrukturen, die eine Zeichenkette aufnehmen, wobei eine Version Byte-Zeichenketten und eine andere Version UTF-16 akzeptiert. Wenn die Abwärtskompatibilität nicht benötigt wird, muss die gesamte Handhabung von Zeichenketten trotzdem geändert werden.
- In UTF-8 kodierter Text ist kleiner als der gleiche in UTF-16 kodierte Text, wenn es mehr Codepunkte unterhalb von U+0080 als im Bereich U+0800..U+FFFF gibt. Dies gilt für alle modernen europäischen Sprachen. Aufgrund der großen Anzahl von Leerzeichen, Zeilenumbrüchen, Ziffern und HTML-Auszeichnungen in typischen Dateien gilt dies häufig sogar für Sprachen wie Chinesisch.
- Die meisten Kommunikations- (z. B. HTML und IP) und Speicherverfahren (z. B. für Unix) wurden für einen Bytestrom entwickelt. Eine UTF-16-Zeichenkette muss für jede Codeeinheit ein Byte-Paar verwenden:
- Die Reihenfolge dieser beiden Bytes wird zu einem Problem und muss im UTF-16-Protokoll festgelegt werden, z. B. durch eine Byte-Order-Markierung.
- Fehlt bei UTF-16 eine ungerade Anzahl von Bytes, ist der gesamte Rest der Zeichenkette bedeutungsloser Text. Bei UTF-8 können die fehlenden Bytes immer noch genau mit dem nächsten Zeichen nach den fehlenden Bytes wiederhergestellt werden. ⓘ
Ableitungen
Die folgenden Implementierungen weisen leichte Abweichungen von der UTF-8-Spezifikation auf. Sie sind mit der UTF-8-Spezifikation nicht kompatibel und können von UTF-8-konformen Anwendungen abgelehnt werden. ⓘ
CESU-8
Der Unicode Technical Report #26 weist den Namen CESU-8 einer nicht standardisierten Variante von UTF-8 zu, bei der Unicode-Zeichen in zusätzlichen Ebenen mit sechs Bytes kodiert werden, anstatt mit den von UTF-8 geforderten vier Bytes. Bei der CESU-8-Kodierung wird jede Hälfte eines Vier-Byte-UTF-16-Surrogatpaares als Zwei-Byte-UCS-2-Zeichen behandelt, was zwei Drei-Byte-UTF-8-Zeichen ergibt, die zusammen das ursprüngliche Zusatzzeichen darstellen. Unicode-Zeichen innerhalb der Basic Multilingual Plane erscheinen so, wie sie normalerweise in UTF-8 erscheinen würden. Der Bericht wurde geschrieben, um die Existenz von Daten, die als CESU-8 kodiert sind, anzuerkennen und zu formalisieren, obwohl das Unicode-Konsortium von ihrer Verwendung abrät, und stellt fest, dass ein möglicher absichtlicher Grund für die CESU-8-Kodierung die Erhaltung der binären UTF-16-Kollation ist. ⓘ
Die CESU-8-Kodierung kann aus der Konvertierung von UTF-16-Daten mit zusätzlichen Zeichen in UTF-8 resultieren, wobei Konvertierungsmethoden verwendet werden, die von UCS-2-Daten ausgehen, d. h., sie kennen die vier Byte langen UTF-16-Zusatzzeichen nicht. Dieses Problem tritt vor allem bei Betriebssystemen auf, die intern weitgehend UTF-16 verwenden, wie z. B. Microsoft Windows. ⓘ
In der Oracle-Datenbank wird die UTF8
Zeichensatz die CESU-8-Kodierung und ist veraltet. Die AL32UTF8
verwendet die standardkonforme UTF-8-Kodierung und wird bevorzugt. ⓘ
CESU-8 ist für die Verwendung in HTML5-Dokumenten verboten. ⓘ
MySQL utf8mb3
In MySQL wird der utf8mb3
Zeichensatz als UTF-8-kodierte Daten mit maximal drei Bytes pro Zeichen definiert, was bedeutet, dass nur Unicode-Zeichen in der Basic Multilingual Plane (d.h. von UCS-2) unterstützt werden. Unicode-Zeichen in zusätzlichen Ebenen werden ausdrücklich nicht unterstützt. utf8mb3
ist veraltet zu Gunsten von utf8mb4
veraltet, der die standardkonforme UTF-8-Kodierung verwendet. utf8
ist ein Alias für utf8mb3
, soll aber in einer zukünftigen Version von MySQL zu einem Alias für utf8mb4
in einer zukünftigen Version von MySQL werden. Es ist möglich, wenn auch nicht unterstützt, CESU-8-kodierte Daten in utf8mb3
zu speichern, indem UTF-16-Daten mit zusätzlichen Zeichen so behandelt werden, als ob sie UCS-2 wären. ⓘ
Geändertes UTF-8
Modifiziertes UTF-8 (MUTF-8) hat seinen Ursprung in der Programmiersprache Java. In Modified UTF-8 verwendet das Null-Zeichen (U+0000) die Zwei-Byte-Überlängenkodierung 11000000 10000000 (hexadezimal C0 80) anstelle von 00000000 (hexadezimal 00). Modifizierte UTF-8-Zeichenfolgen enthalten niemals tatsächliche Null-Bytes, sondern können alle Unicode-Codepunkte einschließlich U+0000 enthalten, so dass solche Zeichenfolgen (mit einem angehängten Null-Byte) von herkömmlichen Funktionen für Zeichenfolgen mit Null-Ende verarbeitet werden können. Alle bekannten Modified UTF-8-Implementierungen behandeln auch die Surrogatpaare wie in CESU-8. ⓘ
Bei normaler Verwendung unterstützt die Sprache Standard UTF-8 beim Lesen und Schreiben von Strings durch InputStreamReader
und OutputStreamWriter
(wenn dies der Standardzeichensatz der Plattform ist oder vom Programm angefordert wird). Für die Serialisierung von Objekten und andere Anwendungen von DataInput
und DataOutput
, für die Java Native Interface und für die Einbettung von konstanten Strings in Klassendateien wird jedoch modifiziertes UTF-8 verwendet. ⓘ
Das von Dalvik definierte dex-Format verwendet ebenfalls modifiziertes UTF-8, um String-Werte darzustellen. Tcl verwendet ebenfalls das gleiche modifizierte UTF-8 wie Java für die interne Darstellung von Unicode-Daten, verwendet aber striktes CESU-8 für externe Daten. ⓘ
WTF-8
In WTF-8 (Wobbly Transformation Format, 8-bit) sind ungepaarte Surrogat-Hälften (U+D800 bis U+DFFF) erlaubt. Dies ist notwendig, um möglicherweise ungültiges UTF-16 zu speichern, wie z. B. Windows-Dateinamen. Viele Systeme, die mit UTF-8 umgehen, arbeiten auf diese Weise, ohne es als eine andere Kodierung zu betrachten, da es einfacher ist. ⓘ
(Der Begriff "WTF-8" wurde auch scherzhaft verwendet, um sich auf fälschlicherweise doppelt kodiertes UTF-8 zu beziehen, manchmal mit der Implikation, dass nur CP1252-Bytes kodiert sind). ⓘ
PEP 383
Version 3 der Programmiersprache Python behandelt jedes Byte eines ungültigen UTF-8 Bytestroms als Fehler (siehe auch Änderungen mit dem neuen UTF-8 Modus in Python 3.7); dies ergibt 128 verschiedene mögliche Fehler. Es wurden Erweiterungen geschaffen, die es ermöglichen, jede Bytefolge, die als UTF-8 angenommen wird, verlustfrei in UTF-16 oder UTF-32 umzuwandeln, indem die 128 möglichen Fehlerbytes in reservierte Codepunkte übersetzt werden, und diese Codepunkte wieder in Fehlerbytes umgewandelt werden, um UTF-8 auszugeben. Der gebräuchlichste Ansatz besteht darin, die Codes in U+DC80...U+DCFF zu übersetzen, die niedrige (nachgestellte) Surrogatwerte und somit "ungültiges" UTF-16 sind, wie es von Pythons PEP 383 (oder "surrogateescape"-Ansatz) verwendet wird. Eine andere Kodierung namens MirBSD OPTU-8/16 konvertiert sie in U+EF80...U+EFFF in einer Private Use Area. Bei beiden Ansätzen wird der Byte-Wert in den niedrigen acht Bits des Ausgabecodepunkts kodiert. ⓘ
Diese Kodierungen sind sehr nützlich, weil sie die Notwendigkeit, sich mit "ungültigen" Byte-Strings zu befassen, bis zu einem späteren Zeitpunkt, wenn überhaupt, vermeiden und es ermöglichen, dass "Text" und "Daten" Byte-Arrays das gleiche Objekt sind. Wenn ein Programm intern UTF-16 verwenden will, sind diese erforderlich, um Dateinamen zu erhalten und zu verwenden, die ungültiges UTF-8 verwenden können; da die Windows-Dateisystem-API UTF-16 verwendet, ist die Notwendigkeit, ungültiges UTF-8 zu unterstützen, geringer. ⓘ
Damit die Kodierung umkehrbar ist, müssen die Standard-UTF-8-Kodierungen der für fehlerhafte Bytes verwendeten Codepunkte als ungültig betrachtet werden. Dies macht die Kodierung inkompatibel mit WTF-8 oder CESU-8 (allerdings nur für 128 Codepunkte). Bei der Neukodierung muss auf Sequenzen von Fehlercodepunkten geachtet werden, die in gültiges UTF-8 zurückkonvertiert werden, was von bösartiger Software genutzt werden kann, um unerwartete Zeichen in der Ausgabe zu erhalten, obwohl dies keine ASCII-Zeichen erzeugen kann, so dass es als vergleichsweise sicher gilt, da bösartige Sequenzen (wie Cross-Site-Scripting) normalerweise auf ASCII-Zeichen angewiesen sind. ⓘ
Darstellung in Editoren
Nicht im Unicodeblock Basis-Lateinisch enthaltene Zeichen
Die Buchstaben des lateinischen Grundalphabets sowie die wichtigsten Satzzeichen werden in UTF-8 und ISO-8859-* identisch angezeigt. Probleme mit der falsch gewählten Zeichencodierung treten bei den anderen Zeichen auf, beispielsweise bei Umlauten. In deutschsprachigen Texten treten diese Zeichen jedoch nur vereinzelt auf, sodass der Text zwar stark entstellt wirkt, aber meist noch lesbar bleibt. ⓘ
In UTF-8 bestehen die Umlaute des deutschen Alphabets (sofern sie in der Normalform NFC vorliegen, also als precomposed character) und das ß aus zwei Bytes; nach ISO 8859 wird jedes Zeichen als 1 Byte codiert und jedes Byte beim Lesen in ein Zeichen transformiert. Das in der UTF-8-Kodierung dieser Buchstaben gemeinsame erste Byte C3hex wird, wie der Tabelle zu entnehmen ist, jeweils unterschiedlich decodiert, ebenso das weitere Byte der Codierung von äöü, dagegen wird bei ÄÖÜß das zweite Byte nicht oder mit dem gleichen Fehler-Zeichen dargestellt, weil 7Fhex bis 9Fhex in ISO 8859 nicht definiert sind, was die Lesbarkeit des Textes zusätzlich erschwert. ⓘ
Bei der Interpretation eines in ISO-8859-codierten Textes als UTF-8 führen die Buchstaben öü zur Anzeige eines Ersetzungszeichens, weil der entsprechende Byte-Wert, wie der Tabelle unten zu entnehmen ist, nicht definiert ist. Bei den Buchstaben äöüß wird ein Start-Byte angenommen und versucht, das nächste Byte als Folgebyte gemeinsam als ein Zeichen zu interpretieren. Das scheitert natürlich häufig, weil die Codierungen der meisten Buchstaben keine gültigen Folgebytes sind. Bei einem ä wird sogar versucht, die nächsten beiden Bytes als Folgebyte zu interpretieren, was aus denselben Gründen regelmäßig scheitert. Je nach Programmierung des anzeigenden Programms verschwinden womöglich entsprechend viele Buchstaben aus dem Text. ⓘ
UTF-8 | ISO-8859-1 | ISO-8859-15 | UTF16 ⓘ | ||
---|---|---|---|---|---|
U+00E4 | C3A4hex | ä | ä | À | 쎤 |
U+00F6 | C3B6hex | ö | ö | ö | 쎶 |
U+00FC | C3BChex | ü | ü | ÃŒ | 쎼 |
U+00DF | C39Fhex | ß | Ã | Ã | 쎟 |
U+00C4 | C384hex | Ä | Ã | Ã | 쎄 |
U+00D6 | C396hex | Ö | Ã | Ã | 쎖 |
U+00DC | C39Chex | Ü | Ã | Ã | 쎜 |
ISO-Latin- | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | UTF-8 ⓘ | ||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
ISO/IEC 8859- | 1 | 2 | 3 | 4 | 9 | 10 | 13 | 14 | 15 | 16 | |||||
1010 0100 | 244 | 164 | A4 | ¤ | ¤ | Ī | ¤ | Ċ | € | Folgebyte | +24 | ||||
1011 0110 | 266 | 182 | B6 | ¶ | ś | ĥ | ļ | ¶ | ķ | ¶ | Folgebyte | +36 | |||
1011 1100 | 274 | 188 | BC | ¼ | ź | ĵ | ŧ | ¼ | ž | ¼ | ỳ | Œ | Folgebyte | +3C | |
1100 0011 | 303 | 195 | C3 | Ã | Ă | Ã | Ć | Ã | Ă | Startbyte | Latin 0080 | ||||
1100 0100 | 304 | 196 | C4 | Ä | Startbyte | Latin 00C0 | |||||||||
1101 0110 | 326 | 214 | D6 | Ö | Startbyte | Hebrew 0580 | |||||||||
1101 1100 | 334 | 220 | DC | Ü | Startbyte | Syriac 0700 | |||||||||
1101 1111 | 337 | 223 | DF | ß | Startbyte | N'Ko 07C0 | |||||||||
1110 0100 | 344 | 228 | E4 | ä | Startbyte | Kana 3000 | |||||||||
1111 0110 | 366 | 246 | F6 | ö | unzulässig | ||||||||||
1111 1100 | 374 | 252 | FC | ü | unzulässig | ||||||||||
Bin | Oct | Dec | Hex | ISO-Latin-ISO/IEC 8859- | UTF-8 |
Ein Beispiel für das Wort Höhe:
- UTF-8-Text in ISO-8859-1/9/13-16-Umgebung
- Höhe → Höhe.
- ISO-8859-1-Text in UTF-8-Umgebung
- Höhe → H�he bzw. Fehlermeldung mit Abbruch. Ein Byte mit dem Hexadezimalwert F6 ist in UTF-8 nicht zulässig. Es ist üblich, für nicht konvertierbare Zeichen das Ersetzungszeichen (U+FFFD) einzufügen. ⓘ