Kodierungen

Grundlagen

Eine Zeichenkodierung, oft einfach als Kodierung bezeichnet, ist eine Abbildung zwischen

Einige Zeichensätze enthalten nur 1-Byte-Zeichen; US-ASCII beispielsweise hat 256 1-Byte-Zeichen. Diese Zeichenkette, in US-ASCII kodiert, hat sechs Zeichen, die als sechs Bytes gespeichert werden.

s = 'Hello!'.encode(Encoding::US_ASCII)  # => "Hello!"
s.encoding                               # => #<Encoding:US-ASCII>
s.bytes                                  # => [72, 101, 108, 108, 111, 33]

Andere Kodierungen können Mehrbyte-Zeichen beinhalten. UTF-8 beispielsweise kodiert mehr als eine Million Zeichen und kodiert jedes in einem bis vier Bytes. Die niedrigsten Werte dieser Zeichen entsprechen ASCII-Zeichen und sind daher 1-Byte-Zeichen.

s = 'Hello!' # => "Hello!"
s.bytes      # => [72, 101, 108, 108, 111, 33]

Andere Zeichen, wie das Euro-Symbol, sind Mehrbyte-Zeichen.

s = "\u20ac" # => "€"
s.bytes      # => [226, 130, 172]

Die Klasse Encoding

Encoding-Objekte

Ruby-Kodierungen werden durch Konstanten in der Klasse Encoding definiert. Für jede dieser Konstanten kann es nur eine Instanz von Encoding geben. Die Methode Encoding.list gibt ein Array von Encoding-Objekten zurück (eines für jede Konstante).

Encoding.list.size        # => 103
Encoding.list.first.class # => Encoding
Encoding.list.take(3)
# => [#<Encoding:ASCII-8BIT>, #<Encoding:UTF-8>, #<Encoding:US-ASCII>]

Namen und Aliase

Die Methode Encoding#name gibt den Namen einer Kodierung zurück.

Encoding::ASCII_8BIT.name  # => "ASCII-8BIT"
Encoding::WINDOWS_31J.name # => "Windows-31J"

Ein Encoding-Objekt hat null oder mehr Aliase; die Methode Encoding#names gibt ein Array zurück, das den Namen und alle Aliase enthält.

Encoding::ASCII_8BIT.names
# => ["ASCII-8BIT", "BINARY"]
Encoding::WINDOWS_31J.names
#=> ["Windows-31J", "CP932", "csWindows31J", "SJIS", "PCK"]

Die Methode Encoding.aliases gibt eine Hash-Tabelle aller Alias/Namen-Paare zurück.

Encoding.aliases.size # => 71
Encoding.aliases.take(3)
# => [["BINARY", "ASCII-8BIT"], ["CP437", "IBM437"], ["CP720", "IBM720"]]

Die Methode Encoding.name_list gibt ein Array aller Kodierungsnamen und Aliase zurück.

Encoding.name_list.size # => 175
Encoding.name_list.take(3)
# => ["ASCII-8BIT", "UTF-8", "US-ASCII"]

Die Methode name_list gibt mehr Einträge zurück als die Methode list, da sie sowohl die Namen als auch ihre Aliase enthält.

Die Methode Encoding.find gibt das Encoding für einen gegebenen Namen oder Alias zurück, falls es existiert.

Encoding.find("US-ASCII")       # => #<Encoding:US-ASCII>
Encoding.find("US-ASCII").class # => Encoding

Standard-Kodierungen

Die Methode Encoding.find (siehe oben) gibt auch eine Standard-Kodierung für jeden dieser speziellen Namen zurück.

Die Methode Encoding.default_external gibt die Standard-Externe Kodierung zurück.

Encoding.default_external # => #<Encoding:UTF-8>

Die Methode Encoding.default_external= setzt diesen Wert.

Encoding.default_external = Encoding::US_ASCII # => #<Encoding:US-ASCII>
Encoding.default_external                      # => #<Encoding:US-ASCII>

Die Methode Encoding.default_internal gibt die Standard-Interne Kodierung zurück.

Encoding.default_internal # => nil

Die Methode Encoding.default_internal= setzt die Standard-Interne Kodierung.

Encoding.default_internal = Encoding::US_ASCII # => #<Encoding:US-ASCII>
Encoding.default_internal                      # => #<Encoding:US-ASCII>

Kompatible Kodierungen

Die Methode Encoding.compatible? gibt zurück, ob zwei gegebene Objekte Encoding-kompatibel sind (d. h., ob sie verkettet werden können); gibt die Kodierung der verketteten Zeichenkette zurück oder nil, wenn sie nicht kompatibel sind.

rus = "\u{442 435 441 442}"
eng = 'text'
Encoding.compatible?(rus, eng) # => #<Encoding:UTF-8>

s0 = "\xa1\xa1".force_encoding(Encoding::ISO_8859_1) # => "\xA1\xA1"
s1 = "\xa1\xa1".force_encoding(Encoding::EUCJP)      # => "\x{A1A1}"
Encoding.compatible?(s0, s1)                         # => nil

String-Kodierung

Ein Ruby String-Objekt hat eine Kodierung, die eine Instanz der Klasse Encoding ist. Die Kodierung kann mit der Methode String#encoding abgerufen werden.

Die Standardkodierung für eine Zeichenkettenkonstante ist die Skriptkodierung; siehe Skriptkodierung.

's'.encoding # => #<Encoding:UTF-8>

Die Standardkodierung für eine mit der Methode String.new erstellte Zeichenkette ist

In jedem Fall kann jede Kodierung angegeben werden.

s = String.new(encoding: Encoding::UTF_8)         # => ""
s.encoding                                        # => #<Encoding:UTF-8>
s = String.new('foo', encoding: Encoding::BINARY) # => "foo"
s.encoding                                        # => #<Encoding:BINARY (ASCII-8BIT)>

Die Kodierung eines Strings kann geändert werden.

s = "R\xC3\xA9sum\xC3\xA9"              # => "Résumé"
s.encoding                              # => #<Encoding:UTF-8>
s.force_encoding(Encoding::ISO_8859_1)  # => "R\xC3\xA9sum\xC3\xA9"
s.encoding                              # => #<Encoding:ISO-8859-1>

Das Ändern der zugewiesenen Kodierung ändert nicht den Inhalt des Strings; es ändert nur die Art und Weise, wie der Inhalt interpretiert werden soll.

s                                 # => "R\xC3\xA9sum\xC3\xA9"
s.force_encoding(Encoding::UTF_8) # => "Résumé"

Der tatsächliche Inhalt eines Strings kann ebenfalls geändert werden; siehe String transkodieren.

Hier sind ein paar nützliche Abfragemethoden.

s = "abc".force_encoding(Encoding::UTF_8)         # => "abc"
s.ascii_only?                                     # => true
s = "abc\u{6666}".force_encoding(Encoding::UTF_8) # => "abc晦"
s.ascii_only?                                     # => false

s = "\xc2\xa1".force_encoding(Encoding::UTF_8)    # => "¡"
s.valid_encoding?                                 # => true
s = "\xc2".force_encoding(Encoding::UTF_8)        # => "\xC2"
s.valid_encoding?                                 # => false

Symbol- und Regexp-Kodierungen

Der in einem Symbol- oder Regexp-Objekt gespeicherte String hat ebenfalls eine Kodierung; die Kodierung kann mit den Methoden Symbol#encoding oder Regexp#encoding abgerufen werden.

Die Standardkodierung für diese ist jedoch

Dateisystem-Kodierung

Die Dateisystem-Kodierung ist die Standard-Encoding für einen String aus dem Dateisystem.

Encoding.find("filesystem") # => #<Encoding:UTF-8>

Locale-Kodierung

Die Locale-Kodierung ist die Standardkodierung für einen String aus der Umgebung, außer aus dem Dateisystem.

Encoding.find('locale') # => #<Encoding:IBM437>

Stream-Kodierungen

Bestimmte Stream-Objekte können zwei Kodierungen haben; diese Objekte umfassen Instanzen von

Die beiden Kodierungen sind

Externe Kodierung

Die externe Kodierung, die ein Encoding-Objekt ist, gibt an, wie aus dem Stream gelesene Bytes als Zeichen interpretiert werden sollen.

Die Standard-Externe Kodierung ist

Die Standard-Externe Kodierung wird von der Methode Encoding.default_external zurückgegeben und kann durch

Sie können die Standard-Externe Kodierung auch mit der Methode Encoding.default_external= setzen, aber dies kann zu Problemen führen; Strings, die vor und nach der Änderung erstellt werden, können unterschiedliche Kodierungen haben.

Für ein IO- oder File-Objekt kann die externe Kodierung durch

Für ein IO-, File-, ARGF- oder StringIO-Objekt kann die externe Kodierung durch

Interne Kodierung

Die interne Kodierung, die ein Encoding-Objekt oder nil ist, gibt an, wie aus dem Stream gelesene Zeichen in Zeichen der internen Kodierung konvertiert werden sollen; diese Zeichen werden zu einer Zeichenkette, deren Kodierung auf die interne Kodierung gesetzt wird.

Die Standard-Interne Kodierung ist nil (keine Konvertierung). Sie wird von der Methode Encoding.default_internal zurückgegeben und kann durch

Sie können die Standard-Interne Kodierung auch mit der Methode Encoding.default_internal= setzen, aber dies kann zu Problemen führen; Strings, die vor und nach der Änderung erstellt werden, können unterschiedliche Kodierungen haben.

Für ein IO- oder File-Objekt kann die interne Kodierung durch

Für ein IO-, File-, ARGF- oder StringIO-Objekt kann die interne Kodierung durch

Skriptkodierung

Ein Ruby-Skript hat eine Skriptkodierung, die durch

__ENCODING__ # => #<Encoding:UTF-8>

abgerufen werden kann. Die Standard-Skriptkodierung ist UTF-8; eine Ruby-Quelldatei kann ihre Skriptkodierung mit einem Magic-Comment in der ersten Zeile der Datei (oder der zweiten Zeile, wenn in der ersten eine Shebang steht) festlegen. Der Kommentar muss das Wort coding oder encoding enthalten, gefolgt von einem Doppelpunkt, einem Leerzeichen und dem Namen oder Alias der Encoding.

# encoding: ISO-8859-1
__ENCODING__ #=> #<Encoding:ISO-8859-1>

Transkodierung

Transkodierung ist der Prozess der Änderung einer Zeichenfolge von einer Kodierung in eine andere.

Soweit möglich bleiben die Zeichen gleich, aber die Bytes, die sie repräsentieren, können sich ändern.

Die Behandlung von Zeichen, die in der Zielkodierung nicht dargestellt werden können, kann durch @Encoding+Options angegeben werden.

String transkodieren

Jede dieser Methoden transkodiert einen String:

Stream transkodieren

Jede dieser Methoden kann einen Stream transkodieren; ob sie dies tut, hängt von den externen und internen Kodierungen ab.

Dieses Beispiel schreibt einen String in eine Datei, kodiert ihn als ISO-8859-1, liest dann die Datei in einen neuen String ein und kodiert ihn als UTF-8.

s = "R\u00E9sum\u00E9"
path = 't.tmp'
ext_enc = Encoding::ISO_8859_1
int_enc = Encoding::UTF_8

File.write(path, s, external_encoding: ext_enc)
raw_text = File.binread(path)

transcoded_text = File.read(path, external_encoding: ext_enc, internal_encoding: int_enc)

p raw_text
p transcoded_text

Ausgabe

"R\xE9sum\xE9"
"Résumé"

Encoding-Optionen

Eine Reihe von Methoden im Ruby-Kern akzeptieren Schlüsselwortargumente als Encoding-Optionen.

Einige der Optionen geben eine Ersetzungszeichenkette an oder verwenden sie bei bestimmten Transkodierungsoperationen. Eine Ersetzungszeichenkette kann in jeder Kodierung vorliegen, die in die Kodierung der Zielzeichenkette konvertiert werden kann.

Diese Schlüssel-Wert-Paare geben Encoding-Optionen an: