Textkodierungen erklärt: UTF-8, Base64 und URL-Kodierung

Aktualisiert:

Computer speichern und senden Bytes, keine Buchstaben. Jedes Mal, wenn Text gespeichert, gesendet oder in eine Webadresse eingefügt wird, muss etwas festlegen, welche Bytes für welche Zeichen stehen, und manchmal müssen die Bytes selbst umgeschrieben werden, damit sie unbeschadet ankommen. Drei Kodierungen erledigen den größten Teil dieser Arbeit: UTF-8 macht aus Zeichen Bytes, Base64 macht aus beliebigen Bytes gewöhnliche Buchstaben und Ziffern, und die Prozentkodierung macht Text innerhalb einer URL sicher.

Dieser letzte Teil der Reihe erklärt jede davon mit Beispielen, die sich Byte für Byte nachprüfen lassen, und verbindet sie mit den Problemen aus den Teilen über JSON und CSV: der Bytereihenfolge-Markierung und Akzenten, aus denen ã wird.

Zeichen, Codepunkte und Bytes

Unicode gibt jedem Zeichen eine Nummer, den Codepunkt, geschrieben als U+ gefolgt von Hexadezimalziffern: A ist U+0041, é ist U+00E9, € ist U+20AC und das Emoji 😀 ist U+1F600. Der Bereich reicht von U+0000 bis U+10FFFF. Eine Kodierung legt fest, wie diese Nummern als Bytes gespeichert werden.

UTF-8, definiert in RFC 3629 (seit November 2003 ein Internetstandard), verwendet ein bis vier Bytes pro Zeichen. Die 128 ASCII-Zeichen behalten ihr einzelnes Byte, sodass englischer Text ohne Sonderzeichen in ASCII und UTF-8 identisch ist; andere Zeichen belegen zwei, drei oder vier Bytes:

UTF-8 ist heute fast überall der Standard: W3Techs fand es im Oktober 2026 auf 99,1 % der Websites, deren Kodierung es ermitteln konnte. In Programmen gibt es aber weiterhin andere Kodierungen. JavaScript-Strings etwa werden in UTF-16 gespeichert, in 16-Bit-Einheiten, und MDN merkt an, dass ein Zeichen oberhalb von U+FFFF zwei davon belegt. Deshalb zählt dasselbe Emoji auf dem Bildschirm als 1 Zeichen, in der JavaScript-Länge als 2 und in UTF-8 als 4 Bytes, und deshalb stimmen Grenzen in Zeichen und in Bytes selten überein.

Die Bytereihenfolge-Markierung

Die Bytereihenfolge-Markierung (BOM), U+FEFF, kann ganz am Anfang einer Datei stehen. In UTF-8 sind das immer die drei Bytes EF BB BF. UTF-8 hat keine Bytereihenfolge, die markiert werden müsste, daher dient sie dort nur als Signatur, die sagt, dass die Datei UTF-8 ist. Das Unicode-Konsortium rät davon ab, wenn ein Protokoll oder Programm bestimmte Zeichen am Dateianfang erwartet.

Die beiden früheren Teile der Reihe begegnen ihr von entgegengesetzten Seiten. JSON, das über ein Netzwerk gesendet wird, darf nicht damit beginnen, und JSON.parse in JavaScript lehnt Text ab, der damit beginnt. Excel dagegen braucht sie, um eine UTF-8-CSV per Doppelklick richtig zu öffnen. Ob man sie hinzufügt, hängt davon ab, welches Programm die Datei liest.

Base64: beliebige Bytes als Text

Manche Stellen akzeptieren nur Text: der Text einer E-Mail, ein JSON-String, ein HTML-Attribut. Base64, festgelegt in RFC 4648 (Oktober 2006), lässt beliebige Bytes, auch ein Bild oder ein PDF, durch sie hindurch. Es nimmt die Eingabe in Gruppen von drei Bytes (24 Bit) und schreibt jede Gruppe als vier Zeichen aus einem Alphabet von 64: A–Z, a–z, 0–9, + und /. Ist die letzte Gruppe unvollständig, füllt = sie auf. Das sind die Testvektoren des RFC:

Vier Zeichen für je drei Bytes bedeutet, dass Base64 ein Drittel größer ist als das Original: Aus einer Datei mit 3.000.000 Bytes werden 4.000.000 Zeichen. E-Mail (MIME) bricht Base64 außerdem in Zeilen von höchstens 76 Zeichen um, was noch etwas hinzufügt.

Base64 ist eine Kodierung, keine Verschlüsselung. Jeder kann es dekodieren, ohne Schlüssel, es schützt also nichts. Wirkt ein Passwort oder Token nur deshalb unlesbar, weil es in Base64 vorliegt, ist es nicht geschützt.

Text muss zu Bytes werden, bevor er in Base64 kodiert werden kann, daher hängt das Ergebnis von der Textkodierung ab. Der Buchstabe é ergibt aus seinen zwei UTF-8-Bytes w6k=, aus seinem einzelnen Byte in Latin-1 aber 6Q==. web.dev weist darauf hin, dass die browsereigene Funktion btoa() nur Zeichen annimmt, die in ein Byte passen, und bei anderen wie € einen Fehler auslöst; Text muss zuerst in UTF-8-Bytes umgewandelt werden. Das Base64-Werkzeug von nTools kodiert Text als UTF-8 und zeigt beim Dekodieren an, ob die Bytes UTF-8 oder Windows-1252 waren.

Base64-Kodierer / -Dekodierer

base64url: die Variante für Webadressen

Zwei der Base64-Zeichen machen außerhalb von normalem Text Ärger. In einer URL kann + als Leerzeichen gelesen werden, und / trennt Pfadabschnitte; in einem Dateinamen ist / gar nicht erlaubt. RFC 4648 definiert deshalb ein zweites Alphabet, das für URLs und Dateinamen sichere, meist base64url genannt, das stattdessen - und _ verwendet. Spezifikationen, die es nutzen, dürfen außerdem die Auffüllung mit = weglassen, was RFC 4648 erlaubt, wenn sie das ausdrücklich festlegen.

JSON Web Tokens sind das bekannteste Beispiel. RFC 7515 definiert ihre Kodierung als base64url ohne jedes abschließende = und ohne Zeilenumbrüche; deshalb können die Teile eines Tokens - und _ enthalten, aber nie +, / oder =. Ein Dekodierer, der nur Standard-Base64 kennt, lehnt solche Strings ab; das nTools-Werkzeug gehört dazu, ersetzen Sie also vor dem Dekodieren - durch + und _ durch /.

Prozentkodierung: Text in einer URL

Eine URL darf nur eine begrenzte Menge an ASCII-Zeichen enthalten, und einige davon haben eine Aufgabe: / trennt den Pfad, ? beginnt die Abfrage, & trennt Parameter, # beginnt das Fragment. RFC 3986 (Januar 2005, Internetstandard) legt die Regeln fest. Buchstaben, Ziffern und - . _ ~ können immer unverändert verwendet werden. Zeichen mit einer Aufgabe werden kodiert, wenn sie Teil eines Werts sind und nicht als Trenner dienen, und jedes Byte außerhalb der erlaubten Menge wird als % gefolgt von zwei Hexadezimalziffern geschrieben. Text wird zuerst in UTF-8 umgewandelt, sodass ein Zeichen außerhalb von ASCII zu mehreren %-Codes wird:

Kodieren Sie die Werte, die Sie in eine URL setzen, nicht die ganze Adresse: Wird https://example.com/?q=1 als ein Wert kodiert, werden : / ? und = zu Codes, was richtig ist, wenn die Adresse selbst Parameter einer anderen URL ist, und falsch, wenn sie als Link funktionieren soll. Die JavaScript-Funktion encodeURIComponent() macht genau diese Kodierung pro Wert und lässt, wie MDN aufführt, außerdem ! ' ( ) und * unkodiert. Das URL-Werkzeug von nTools verwendet sie.

URL-Kodierer / -Dekodierer

Ein + oder %20?

HTML-Formulare senden ihre Daten in einem etwas anderen Format, application/x-www-form-urlencoded, das der URL-Standard der WHATWG definiert. Darin wird ein Leerzeichen als + geschrieben, sodass eine Suche nach a b&c=d als q=a+b%26c%3Dd gesendet wird. Überall sonst in einer URL ist + einfach ein Pluszeichen.

Das erklärt eine häufige Verwechslung: a+b%20c ergibt mit einem allgemeinen URL-Dekodierer a+b c, weil dort nur %20 ein Leerzeichen ist; ein Formular-Dekodierer ergibt a b c. Wählen Sie den Dekodierer, der zur Herkunft des Texts passt. MDN schlägt vor, nach encodeURIComponent() %20 durch + zu ersetzen, wenn Sie das Formularformat brauchen.

Doppelte Kodierung

RFC 3986 warnt, dass ein String nicht mehr als einmal prozentkodiert oder -dekodiert werden darf. Passiert es doch, wird das % jedes Codes erneut als %25 kodiert:

Folgen wie %2520 oder %25C3%25A9 in einer Adresse zeigen, dass etwas bereits kodierten Text noch einmal kodiert hat. Dekodieren Sie einmal, prüfen Sie das Ergebnis und kodieren Sie nur die Teile, die es brauchen.

Welche brauchen Sie?

SituationVerwenden
Text speichern oder senden: Dateien, Webseiten, JSON, CSVUTF-8
Bytes wie ein Bild oder eine Datei in Text einbetten: JSON, E-Mail, HTMLBase64
Base64 in einer URL, einem Dateinamen oder einem Tokenbase64url
Ein Wert in einer URL: ein Suchbegriff, ein Parameter, ein PfadabschnittProzentkodierung
Daten, die ein HTML-Formular sendetFormularkodierung (Leerzeichen als +)
Daten geheim haltenKeine davon: Verschlüsselung verwenden

Häufige Fragen

Ist Base64 eine Form der Verschlüsselung?

Nein. Es ist eine umkehrbare Kodierung, die jeder ohne Schlüssel dekodieren kann. Sie macht Daten als Text transportierbar, nicht vor dem Lesen sicher.

Warum unterscheidet sich mein Base64 von dem eines anderen Werkzeugs?

Meist, weil der Text mit einer anderen Kodierung in Bytes umgewandelt wurde, etwa Latin-1 statt UTF-8, weil ein Werkzeug base64url verwendet oder die Auffüllung mit = weglässt, oder weil eines Zeilenumbrüche einfügt.

Warum zählt ein Emoji als zwei Zeichen?

Viele Programme, darunter JavaScript, zählen 16-Bit-Einheiten von UTF-16, und ein Emoji wie 😀 oberhalb von U+FFFF braucht zwei. In UTF-8 belegt es vier Bytes.

Soll ich Dateien als UTF-8 mit BOM speichern?

Nur wenn das Programm, das die Datei liest, sie braucht, wie Excel bei CSV-Dateien. Für JSON und die meisten Webdateien speichern Sie UTF-8 ohne BOM.

Warum enthält mein Link %2520?

Er wurde zweimal kodiert: %20, ein Leerzeichen, wurde erneut kodiert, und aus seinem % wurde %25. Dekodieren Sie ihn einmal und verwenden Sie das Ergebnis.

Laden die nTools-Kodierer meinen Text hoch?

Nein. Kodieren und Dekodieren laufen in Ihrem Browser, und der Text wird nirgendwohin gesendet.

Zurück in der Reihe ← CSV-Dateien erklärt: Trennzeichen, Anführungszeichen, Kodierung und Excel

Quellen

  1. RFC 3629 — UTF-8, a transformation format of ISO 10646
  2. Unicode Consortium — FAQ: UTF-8, UTF-16, UTF-32 & BOM
  3. W3Techs — Usage statistics of character encodings for websites
  4. MDN — UTF-16 (glossary)
  5. RFC 8259 — The JavaScript Object Notation (JSON) Data Interchange Format
  6. Microsoft Support — Opening CSV UTF-8 files correctly in Excel
  7. RFC 4648 — The Base16, Base32, and Base64 Data Encodings
  8. web.dev — The nuances of base64 encoding strings in JavaScript
  9. RFC 7515 — JSON Web Signature (JWS)
  10. RFC 3986 — Uniform Resource Identifier (URI): Generic Syntax
  11. WHATWG — URL Standard
  12. MDN — encodeURIComponent()

Weitere Ratgeber