Codierung von Textdaten

Nachdem Sie die Binärdarstellung von Ganzzahlen kennengelernt haben: Wie würden Sie einen Namen binär codieren? Überlegen Sie dazu: Wie viele Bits werden pro Zeichen benötigt, um die dafür mindestens benötigten Zeichen zu codieren? Wie könnte der Name “BEA BUX” in dieser Codierung aussehen?

Lösung

Sollen neben Groß- auch Kleinbuchstaben a–z dargestellt werden können, wird ein zusätzliches Bit benötigt, da sich der Zeichenumfang verdoppelt. Mit Ziffern, Satz- und Sonderzeichen wie Währungssymbolen, diakritischen Zeichen (z. B. Umlauten) und anderen Buchstaben des lateinischen Schriftsystems kommen schnell mehrere 100 Zeichen zusammen, für die unterschiedliche Codes benötigt werden. Für eine universelle Zeichencodierung, die auch umfangreichere Symbol- und Schriftsysteme wie das Chinesische oder Japanische umfasst, müssen dagegen mehrere 10 000 bis 100 000 Zeichen codierbar sein. Damit diese Daten eindeutig interpretierbar sind, muss in einem Standard festgelegt werden, durch welche Zahl welches Zeichen repräsentiert wird und wie diese Zahlenwerte binär codiert werden.

In dieser Lektion werden wir uns systematisch mit der Codierung von Textzeichen beschäftigen und die verbreiteten Standards zur Zeichencodierung (z. B. für Textdateien) untersuchen.

Zeichencodierung

Ein Zeichensatz (engl. character set oder kurz charset) beschreibt die Menge der zur Verfügung stehenden Zeichen, die dargestellt werden können, und legt für jedes Zeichen einen Zahlenwert fest. Die darstellbaren Zeichen werden also durchnummeriert. Der feste Zahlenwert eines Zeichens in einem Zeichensatz wird als Codepoint bezeichnet. Codepoints werden in der Regel hexadezimal, aber auch dezimal dargestellt.

Eine Zeichencodierung legt dagegen für jeden Codepoint bestimmte Byte-Werte fest, durch die das Zeichen binär codiert wird. Die früheren Zeichensätze wie ASCII oder ANSI (siehe unten) umfassten nicht mehr als 256 Zeichen, so dass der Unterschied zwischen Codepoint und Zeichencodierung keine Rolle spielte: Hier wurde ein Zeichen einfach durch die Binärdarstellung seines Codepoints codiert. Bei aktuellen Zeichensätzen wie Unicode, die mehrere 100 000 Zeichen umfassen, sind Codepoint und Codierung nicht unbedingt identisch, aber dazu später mehr.

Wie beginnen zunächst mit den einfachen Zeichencodierungen, in denen jedes Zeichen durch 1 Byte codiert wird.

ASCII

Der Standard ASCII (kurz für American Standard Code for Information Interchange) wurde ursprünglich bereits 1963 entwickelt. Er definiert eine 7-Bit-Zeichencodierung, die als Grundlage der meisten heute gebräuchlichen Zeichencodierungen dient. Der ASCII-Zeichensatz umfasst 27 = 128 Zeichen, die als Byte mit führendem 0-Bit dargestellt werden. Dabei stellen nur die Zeichen 32 bis 126 (hexadezimal 20 bis 7E) druckbare Symbole dar.

Die folgende Tabelle zeigt alle Zeichen und ihre Hexadezimal-Codes im ASCII-Zeichensatz (spezielle, meist nicht druckbare Zeichen sind kursiv dargestellt):

Code (hex.)…0…1…2…3…4…5…6…7…8…9…A…B…C…D…E…F
0…NULSOHSTXETXEOTENQACKBELBSHTLFVTFFCRSOSI
1…DLEDC1DC2DC3DC4NAKSYNETBCANEMSUBESCFSGSRSUS
2…SP!"#$%&'()*+,-./
3…0123456789:;<=>?
4…@ABCDEFGHIJKLMNO
5…PQRSTUVWXYZ[\]^_
6…`abcdefghijklmno
7…pqrstuvwxyz{|}~DEL

Das Zeichen SP mit dem Hexadezimal-Code 20 (dezimal 32) stellt dabei das Leerzeichen (engl. space) dar.

Beispiel: Die Zeichenfolge “Hallo, Kiel!” wird im ASCII-Zeichencode durch die Bytefolge 48 61 6C 6C 6F 2C 20 4B 69 65 6C 21 (hexadezimal) repräsentiert.

ZeichenHallo,Kiel!
Code (hex.)48616C6C6F2C204B69656C21
Code (dez.)729710810811144327510510110833

Steuerzeichen

Historisch gesehen baut ASCII auf Zeichencodierungen für Fernschreiber (engl. teletype writer) auf, beispielsweise dem Baudot-Code und insbesondere dem Murray-Code, die wiederum auf Zeichencodierungen für frühere Telegrafen wie dem Morse-Code basieren.

Die ersten 32 Zeichen und das letzte Zeichen im ASCII-Code sind Steuerzeichen für das Ausgabegerät und werden nicht als sichtbare Symbole im Text dargestellt. Diese Steuerzeichen sind historisch durch ihre Verwendung für Fernschreiber begründet, was sich auch an ihren Bezeichnungen erkennen lässt (z. B. “Zeilenvorschub”, “Wagenrücklauf”). Viele dieser Zeichen haben heute in Textdateien keine Bedeutung mehr und können hier ignoriert werden. Für uns sind im Wesentlichen nur die folgenden Steuerzeichen relevant:

Das Tabulator-Zeichen (engl. horizontal tabulator, kurz HT) mit dem Hexadezimal-Code 09 (dez. 9) wird insbesondere in Textdateien verwendet, die Tabellendaten beschreiben, um Daten in einer Zeile voneinander zu trennen. Das Zeichen wird in den meisten Textverarbeitungsprogrammen mit der Tabulator-Taste erzeugt und durch mehrere aufeinanderfolgende Leerzeichen angezeigt.

Ein Zeilenumbruch, der in Textverarbeitungsprogrammen mit der Eingabe-Taste erzeugt wird, wird je nach Betriebssystem unterschiedlich codiert:

  • In Linux, iOS und anderen Unix-ähnlichen Betriebssystemen wird das Zeilenvorschub-Zeichen (engl. line feed, kurz LF) mit dem Hexadezimal-Code 0A (dez. 10) für einen Zeilenumbruch verwendet.
  • In Windows steht vor dem Zeilenvorschub-Zeichen zusätzlich das Wagenrücklauf-Zeichen (engl. carriage return, kurz CR) mit dem Hexadezimal-Code 0D (dez. 13), so dass ein Zeilenumbruch hier immer durch zwei aufeinanderfolgende Bytes repräsentiert wird (hex. 0D 0A).

Erweitertes ASCII

Der ASCII-Zeichensatz wurde ursprünglich nur zur Codierung englischsprachiger Texte entwickelt und enthält daher keinerlei regionale Sonderzeichen wie beispielweise die deutschen Umlaute, das Eszett oder Vokale mit Akzenten – von Buchstaben anderer Alphabete ganz abgesehen.

Aus diesem Grund wurden ab Ende der 1970er verschiedene Standards für Erweiterungen des ASCII-Zeichensatzes veröffentlicht, in denen die übrigen 128 Zeichen, die bei einer 8-Bit-Codierung festgelegt werden können, für verschiedene regionale Schriftsysteme festgelegt wurden. Die bekanntesten dieser Erweiterungen sind zum einen die ISO 8859-Codierungen, zum anderen die Windows Codepages, deren jeweilige Varianten für westeuropäische Sprachen (ISO 8859-1 und Windows-1252) zum Teil auch heute noch (wenn auch im Vergleich zu Unicode in sehr viel geringerem Maße) verwendet werden. Wir betrachten diese beiden Zeichencodierungen hier hauptsächlich deswegen, weil Unicode auf ihnen aufbaut.

ISO 8859-1

Die Normenfamilie ISO 8859 definiert verschiedene 8-Bit-Zeichencodierungen, die den ASCII-Zeichensatz um Sonderzeichen erweitern. Hier werden nur Symbole für die Codepoints 160–255 (hex. A0FF) definiert, die Codepoints 128–159 (hex. 809F) werden nicht festgelegt. Die Normenfamilie umfasst Standards für verschiedene Schriftsysteme (neben Lateinisch z. B. Arabisch, Griechich, Kyrillisch), die als ISO 8859-1 bis 8859-16 bezeichnet sind.

ISO 8859-1 (auch als Latin-1 bezeichnet) ist dabei die Zeichencodierung für westeuropäische Sprachen und die am weitesten verbreitete Variante der ISO 8859-Normen.1

Die folgende Tabelle stellt die zusätzlichen Zeichen im ISO 8859-1-Zeichensatz dar:

Code (hex.)…0…1…2…3…4…5…6…7…8…9…A…B…C…D…E…F
A…NBSP¡¢£¤¥¦§¨©ª«¬SHY®¯
B…°±²³´µ·¸¹º»¼½¾¿
C…ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ
D…ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß
E…àáâãäåæçèéêëìíîï
F…ðñòóôõö÷øùúûüýþÿ

Hier werden zwei weitere gebräuchliche Steuerzeichen definiert:

  • Das Zeichen NBSP mit dem Hexadezimal-Code A0 (dezimal 160) stellt das geschützte Leerzeichen (engl. non-breaking space) dar.
  • Das Zeichen SHY mit dem Hexadezimal-Code AD (dezimal 173) ist das weiche Trennzeichen (engl. soft hyphen).

Beispiel: Die Zeichenfolge “Grüße aus Mölln!” wird in ISO 8859-1 durch die Bytefolge 47 72 FC DF 65 20 61 75 73 20 4D F6 6C 6C 6E 21 (hexadezimal) repräsentiert.

ZeichenGrüßeausMölln!
Code (hex.)4772FCDF6520617573204DF66C6C6E21
Code (dez.)7111425222310132971171153277246108108110

Windows-1252 (ANSI)

Die von Microsoft für das Betriebssystem Windows entwickelten Windows Codepages definieren alternative ASCII-Erweiterungen, die zu großen Teilen identisch mit den ISO 8859-Standards sind. Das Äquivalent zu ISO 8859-1 ist Windows-1252 (auch Codepage 1252 oder Western European). Diese Zeichencodierung wird auch oft ANSI-Zeichencode genannt (ANSI steht für American National Standards Institute).2

Windows-1252 unterscheidet sich von ISO 8859-1 nur darin, dass hier auch druckbare Symbole für die meisten der Codepoints 128–159 (hex. 809F) festlegt werden:

Code (hex.)…0…1…2…3…4…5…6…7…8…9…A…B…C…D…E…F
8…ƒˆŠŒŽ
9…˜šœžŸ

Auf diese Weise entstand eine Vielzahl unterschiedlicher Zeichencodierungen für verschiedene Alphabete, in denen dasselbe 8-Bit-Muster je nach Kontext verschiedene Zeichen bedeuten kann. Neben 8-Bit-Zeichencodierungen entstanden dabei auch Codierungen, die mehr Bits pro Zeichen verwenden, um alle relevanten Zeichen zu codieren, etwa für das chinesische oder japanische Schriftsystem.

Unicode

Der Unicode-Zeichensatz wurde entwickelt, um dem Chaos aus regionalspezifischen Codierungen ein Ende zu bereiten und alle Zeichen in einem Standard zusammenzufassen. Unicode (auch ISO 10646 oder UIC, kurz für Universal Coded Character Set) ist heute der mit Abstand am weitesten verbreitete internationale Standard zur Definition eines global einheitlichen Zeichensatzes.

Ziel des Unicode-Standards ist es, langfristig für jedes Symbol aller weltweit bekannten Schrift- und Zeichensysteme einen Codepoint (“Unicode-Nummer”) festzulegen. Der aktuelle Unicode-Standard (Version 13.0.0, Stand August 2021) umfasst 143 859 Zeichen, darunter neben Schriftzeichen und Währungssymbolen auch geometrische Symbole und Emojis.3

Die ersten 256 Codepoints sind in Unicode identisch mit ASCII und ISO 8859-1 bzw. ANSI (bis auf die Codepoints 128–159, für die in Unicode keine druckbaren Symbole definiert sind, sondern weitere Steuerzeichen).

Da ein Byte hier klarerweise nicht mehr ausreicht, um ein Unicode-Zeichen darzustellen, gibt es verschiedene Standards zur Zeichencodierung, also um die Unicode-Nummern als Byte-Codes darzustellen. Verfahren zur Abbildung von Unicode-Nummern auf Byte-Codes werden als UTF (Unicode Transformation Format) bezeichnet.

UTF-32

Die einfachste, aber auch speicheraufwendigste Methode besteht darin, jedes Unicode-Zeichen mit vier Byte (= 32 Bit) darzustellen, so dass bis zu 232 (also mehr als 4 Mrd.) Zeichen darstellbar sind. Diese Zeichencodierung wird als UTF-32 bezeichnet. Eine UTF-32-codierte Textdatei ist also viermal so groß wie eine mit ANSI oder ISO 8859-1 codierte Datei, auch wenn nur Zeichen aus dem ANSI- bzw. ISO 8859-1-Zeichensatz verwendet werden.

Beispiel: Die Zeichenfolge “Grüße aus Mölln!” wird in ANSI und ISO 8859-1 durch die Bytefolge 47 72 FC DF 65 20 61 75 73 20 4D F6 6C 6C 6E 21 (hexadezimal) repräsentiert, also durch 16 Byte. Wird UTF-32-Codierung verwendet, werden 64 Byte benötigt, nämlich 00 00 00 47 00 00 00 72 00 00 00 FC 00 00 00 DF

UTF-8

Eine bessere Methode besteht darin, variable Codelängen zu verwenden – die Zeichencodierung UTF-8 setzt eine solche Strategie um. UTF-8 ist momentan die mit Abstand am weitesten verbreitete Zeichencodierung für Unicode-Textdateien.4

Hier werden häufiger auftretende Zeichen (geringere Unicode-Nummern) mit weniger Byte codiert als spezielle, seltenere Zeichen (höhere Unicode-Nummern). Das Codierungsverfahren ist folgendermaßen definiert:

  • Beginnt ein Byte mit dem höchsten Bit 0, so codieren die restlichen 7 Bit das entsprechende ASCII-Zeichen.
    0xxx xxxx
  • Beginnt ein Byte dagegen mit der Bitfolge 110, so wird es zusammen mit dem folgenden Byte als Unicode-Zeichen interpretiert. Dabei wird erwartet, dass das folgende Byte mit der Bitfolge 10 beginnt (anderenfalls ist der UTF-8-Code nicht “wohlgeformt”, also bzgl. der Syntaxregeln für UTF-8-Codes formal nicht korrekt). Der Codepoint des Unicode-Zeichens wird durch die letzten 5 Bit des ersten Zeichens und die letzten 6 Bit des zweiten Zeichens gebildet. Auf diese Weise werden mit 11 Bit die Unicode-Zeichen mit den Nummern 128 bis 2047 dargestellt (u. a. Lateinisch, Griechisch, Kyrillisch, Arabisch und Hebräisch).
    110x xxxx 10xx xxxx
  • Beginnt es mit der Bitfolge 1110, wird es mit den beiden folgenden Byte zusammen als Unicode-Zeichen interpretiert. Auf diese Weise werden mit 16 Bit die Unicode-Zeichen mit den Nummern 2048 bis 65 535 dargestellt (u. a. Pfeile, mathematische Symbole, Chinesisch, Japanisch).
    1110 xxxx 10xx xxxx 10xx xxxx
  • Beginnt es mit 11110, wird es mit den folgenden drei Bytes zusammen als Unicode-Zeichen interpretiert. Auf diese Weise werden mit 21 Bit die Unicode-Zeichen mit den Nummern 65 536 bis 2 097 151 dargestellt (u. a. antike Schriftzeichen, Emojis).
    1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx

Ein Unicode-Zeichen wird in UTF-8 also durch ein bis vier Bytes repräsentiert, wobei gewährleistet ist, dass über 2 Mio. Zeichen darstellbar sind (von denen momentan knapp 7% genutzt werden).

Beispiele:

  • Das Unicode-Zeichen Ä hat die Unicode-Nummer C4 (hex.) bzw. 196 (dez.), die Binärdarstellung dieser Zahl ist 1100 0100.
    Die UTF-8-Codierung benötigt also 2 Byte und lautet: 1100 0011 1000 0100 (binär) bzw. C3 84 (hex.).
  • Das Unicode-Zeichen 😀 hat die Unicode-Nummer 1F600 (hex.) bzw. 128 512 (dez.), die Binärdarstellung dieser Zahl ist 1 1111 0110 0000 0000.
    Die UTF-8-Codierung benötigt also 4 Byte und lautet: 1111 0000 1001 1111 1001 1000 1000 0000 (binär) bzw. F0 9F 98 80 (hex.).

Für Textdateien sollte in der Regel immer UTF-8 als Zeichencodierung verwendet werden, sofern Sonderzeichen verwendet werden, die über den ASCII-Zeichensatz hinaus gehen, da dieses Format am gebräuchlichsten ist.

Übungsaufgaben

Aufgabe 1: Zeichencodierung

In einer Textdatei, die im Textbearbeitungsprogramm (fälschlicherweise) mit der Zeichencodierung ISO 8859-1 angezeigt wird, kommt mehrmals die Zeichenfolge ä vor.

Image

  • Welchen Bitcode hat die Zeichenfolge ä in ISO 8859-1?
  • Welche Zeichencodierung ist vermutlich eigentlich richtig für diese Textdatei?
  • Welches Zeichen wird statt ä in der eigentlich richtigen Zeichencodierung dargestellt?

Aufgabe 2: Textdateigröße

Der folgende Text soll als erweiterter ASCII-Code dargestellt werden (ISO 8859-1 oder Windows-1252/ANSI):

Bei UTF-8 werden
1-4 Byte verwendet,
um ein Zeichen zu
speichern.
  • Wie viele Bytes werden zur Darstellung des Textes benötigt?
  • Überprüfen Sie Ihre Vorhersage, indem Sie den Text in einen Texteditor eingeben/kopieren, als Textdatei in einem geeigneten Format (ISO 8859-1 oder Windows-1252/ANSI) speichern und anschließend die Dateigröße überprüfen.
  • Macht es für die Dateigröße einen Unterschied, ob Sie die Textdatei in Windows oder Linux erstellen?
  • Ändert sich die Dateigröße, wenn der Text mit UTF-8 codiert wird?

Aufgabe 3: UTF-8-Codierung

Welches Unicode-Zeichen verbirgt sich hinter dem (hier hexadezimal dargestellten) UTF-8-Code F0 9F 91 8D?

Ermitteln Sie dazu seine Unicode-Nummer aus dem Bitcode und suchen Sie in der Unicode-Zeichentabelle auf https://unicode-table.com/de danach (im Suchfeld oben die Unicode-Nummer als Hexadezimal- oder Dezimalzahl angeben).


  1. Der später eingeführte Standard ISO 8859-15 (auch Latin-9) für westeuropäische Sprachen unterscheidet sich nur in 8 Zeichen von ISO 8859-1 (Latin-1):

    Code (hexadezimal)A4A6A8B4B8BCBDBE
    Zeichen in ISO 8859-1ŠšŽžŒœŸ
    Zeichen in ISO 8859-15¤¦¨´¸¼½¾
     ↩︎
  2. Genauer formuliert: Windows-1252 basiert auf einem früheren Entwurf der ANSI-Zeichencodierung, die später mit Änderungen für die Codepoints 128–159 zu ISO 8859-1 wurde. Die Bezeichnung “ANSI” wird heute aber überwiegend synonym für Windows-1252 verwendet. ↩︎

  3. siehe offizielle Website des Unicode-Konsortiums: https://home.unicode.org ↩︎

  4. So verwenden 2021 über 97% aller Webseiten UTF-8 als Zeichencodierung, siehe https://w3techs.com/technologies/cross/character_encoding/ranking ↩︎