Kodierungen
Grundlagen
Eine Zeichenkodierung, oft einfach als Kodierung bezeichnet, ist eine Abbildung zwischen
-
einer Folge von 8-Bit-Bytes (jedes Byte im Bereich
0..255). -
Zeichen in einem bestimmten Zeichensatz.
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.
-
external: die Standard-Externe Kodierung.Encoding.find("external") # => #<Encoding:UTF-8>
-
internal: die Standard-Interne Kodierung (kannnilsein).Encoding.find("internal") # => nil
-
locale: die Standard-Kodierung für eine Zeichenkette aus der Umgebung.Encoding.find("locale") # => #<Encoding:UTF-8> # Linux Encoding.find("locale") # => #<Encoding:IBM437> # Windows
-
filesystem: die Standard-Kodierung für eine Zeichenkette aus dem Dateisystem.Encoding.find("filesystem") # => #<Encoding:UTF-8>
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
-
ohne Argument: ASCII-8BIT.
-
mit einem String-Objekt als Argument: die Kodierung dieses Strings.
-
für eine Zeichenkettenkonstante: die Skriptkodierung; siehe Skriptkodierung.
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
-
US-ASCII, wenn alle Zeichen US-ASCII sind.
-
die Skriptkodierung, andernfalls; siehe (Skript- Skriptkodierung).
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
-
eine externe Kodierung, die die Kodierung des Streams identifiziert.
-
eine interne Kodierung, die (wenn nicht
nil) die Kodierung angibt, die für die aus dem Stream konstruierte Zeichenkette verwendet werden soll.
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
-
UTF-8 für einen Textstream.
-
ASCII-8BIT für einen Binärstream.
Die Standard-Externe Kodierung wird von der Methode Encoding.default_external zurückgegeben und kann durch
-
Ruby-Kommandozeilenoptionen
--external_encodingoder-Egesetzt werden.
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
-
Open-Optionen
external_encodingoderencodingbeim Erstellen des Objekts gesetzt werden; siehe Open Options.
Für ein IO-, File-, ARGF- oder StringIO-Objekt kann die externe Kodierung durch
-
Methoden
set_encodingoder (außer für ARGF)set_encoding_by_bomgesetzt werden.
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
-
Ruby-Kommandozeilenoptionen
--internal_encodingoder-Egesetzt werden.
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
-
Open-Optionen
internal_encodingoderencodingbeim Erstellen des Objekts gesetzt werden; siehe Open Options.
Für ein IO-, File-, ARGF- oder StringIO-Objekt kann die interne Kodierung durch
-
die Methode
set_encodinggesetzt werden.
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:
-
String#encode: Transkodiertselfin einen neuen String gemäß den angegebenen Kodierungen und Optionen. -
String#encode!: WieString#encode, transkodiert aberselfan Ort und Stelle. -
String#scrub: Transkodiertselfin einen neuen String, indem ungültige Bytefolgen durch eine angegebene oder Standard-Ersetzungszeichenkette ersetzt werden. -
String#scrub!: WieString#scrub, transkodiert aberselfan Ort und Stelle. -
String#unicode_normalize: Transkodiertselfin einen neuen String gemäß der Unicode-Normalisierung. -
String#unicode_normalize!: WieString#unicode_normalize, transkodiert aberselfan Ort und Stelle.
Stream transkodieren
Jede dieser Methoden kann einen Stream transkodieren; ob sie dies tut, hängt von den externen und internen Kodierungen ab.
-
IO.foreach: Gibt jede Zeile des gegebenen Streams an den Block weiter. -
IO.new: Erstellt und gibt ein neues IO-Objekt für den gegebenen ganzzahligen Dateideskriptor zurück. -
IO.open: Erstellt ein neues IO-Objekt. -
IO.pipe: Erstellt ein verbundenes Paar aus Lese- und Schreib-IO-Objekten. -
IO.popen: Erstellt ein IO-Objekt zur Interaktion mit einem Unterprozess. -
IO.read: Gibt einen String mit allen oder einem Teil der Bytes aus dem gegebenen Stream zurück. -
IO.readlines: Gibt ein Array von Strings zurück, die die Zeilen aus dem gegebenen Stream sind. -
IO.write: Schreibt einen gegebenen String in den gegebenen Stream.
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:
-
Für eine ungültige Bytefolge
-
:invalid: nil(Standard): Ausnahme auslösen. -
:invalid: :replace: Jede ungültige Bytefolge durch die Ersetzungszeichenkette ersetzen.
Beispiele
s = "\x80foo\x80" s.encode(Encoding::ISO_8859_3) # Raises Encoding::InvalidByteSequenceError. s.encode(Encoding::ISO_8859_3, invalid: :replace) # => "?foo?"
-
-
Für ein undefiniertes Zeichen
-
:undef: nil(Standard): Ausnahme auslösen. -
:undef: :replace: Jedes undefinierte Zeichen durch die Ersetzungszeichenkette ersetzen.
Beispiele
s = "\x80foo\x80" "\x80".encode(Encoding::UTF_8, Encoding::BINARY) # Raises Encoding::UndefinedConversionError. s.encode(Encoding::UTF_8, Encoding::BINARY, undef: :replace) # => "�foo�"
-
-
Ersetzungszeichenkette
-
:replace: nil(Standard): Ersetzungszeichenkette auf Standardwert setzen:"\uFFFD"("�") für eine Unicode-Kodierung, andernfalls'?'. -
:replace: some_string: Ersetzungszeichenkette auf den gegebenensome_stringsetzen; überschreibt:fallback.
Beispiele
s = "\xA5foo\xA5" options = {:undef => :replace, :replace => 'xyzzy'} s.encode(Encoding::UTF_8, Encoding::ISO_8859_3, **options) # => "xyzzyfooxyzzy"
-
-
Fallback für Ersetzung
Eine der folgenden Optionen kann angegeben werden:
-
:fallback: nil(Standard): Kein Fallback für Ersetzung. -
:fallback: hash_like_object: Fallback für Ersetzung auf das gegebenehash_like_objectsetzen; die Ersetzungszeichenkette isthash_like_object[X]. -
:fallback: method: Fallback für Ersetzung auf die gegebenemethodsetzen; die Ersetzungszeichenkette istmethod(X). -
:fallback: proc: Fallback für Ersetzung auf den gegebenenprocsetzen; die Ersetzungszeichenkette istproc[X].
Beispiele
s = "\u3042foo\u3043" hash = {"\u3042" => 'xyzzy'} hash.default = 'XYZZY' s.encode(Encoding::US_ASCII, fallback: hash) # => "xyzzyfooXYZZY" def (fallback = "U+%.4X").escape(x) self % x.unpack("U") end "\u{3042}".encode(Encoding::US_ASCII, fallback: fallback.method(:escape)) # => "U+3042" proc = Proc.new {|x| x == "\u3042" ? 'xyzzy' : 'XYZZY' } s.encode('ASCII', fallback: proc) # => "XYZZYfooXYZZY"
-
-
XML-Entitäten
Eine der folgenden Optionen kann angegeben werden:
-
:xml: nil(Standard): Keine Behandlung von XML-Entitäten. -
:xml: :text: Quelltext als XML behandeln; jedes undefinierte Zeichen durch seine großgeschriebene hexadezimale numerische Zeichenreferenz ersetzen, außer dass-
&durch&ersetzt wird. -
<durch<ersetzt wird. -
>durch>ersetzt wird.
-
-
:xml: :attr: Quelltext als XML-Attributwert behandeln; jedes undefinierte Zeichen durch seine großgeschriebene hexadezimale numerische Zeichenreferenz ersetzen, außer dass-
die Ersetzungszeichenkette
rdoppelt zitiert wird ("r"). -
Jedes eingebettete doppelte Anführungszeichen wird durch
"ersetzt. -
&durch&ersetzt wird. -
<durch<ersetzt wird. -
>durch>ersetzt wird.
-
Beispiele
s = 'foo"<&>"bar' + "\u3042" s.encode(Encoding::US_ASCII, xml: :text) # => "foo\"<&>\"barあ" s.encode(Encoding::US_ASCII, xml: :attr) # => "\"foo"<&>"barあ\""
-
-
Newlines
Eine der folgenden Optionen kann angegeben werden:
-
:cr_newline: true: Jedes Zeilenumbruchzeichen ("\n") durch ein Wagenrücklaufzeichen ("\r") ersetzen. -
:crlf_newline: true: Jedes Zeilenumbruchzeichen ("\n") durch eine Wagenrücklauf/Zeilenumbruch-Zeichenkette ("\r\n") ersetzen. -
:universal_newline: true: Jedes Wagenrücklaufzeichen ("\r") und jede Wagenrücklauf/Zeilenumbruch-Zeichenkette ("\r\n") durch ein Zeilenumbruchzeichen ("\n") ersetzen.
Beispiele
s = "\n \r \r\n" # => "\n \r \r\n" s.encode(Encoding::US_ASCII, cr_newline: true) # => "\r \r \r\r" s.encode(Encoding::US_ASCII, crlf_newline: true) # => "\r\n \r \r\r\n" s.encode(Encoding::US_ASCII, universal_newline: true) # => "\n \n \n"
-