JavaScript: TextEncoder und TextDecoder, Strings und ArrayBuffer

Anwendungsbeispiele für TextEncoder, TextDecoder zum Konvertieren von Text und ein Wrapper zum Delegieren der Methoden

Die Methode TextDecoder.decode() macht aus einer Bytesequenez (ArrayBuffer, Uint8Array) lesbare Zeichen, also eine Zeichenkette die in das DOM eingebaut werden kann. Per Default ist UTF-8 die eingestellte Kodierung, von daher nimmt decode() diesen Algorithmus womit das DOM die Sequenz aus dem ArrayBuffer als eine UTF-8-kodierte Zeichenfolge auffasst. Bekanntlich haben Bytesequenzen von Zeichen mit Codepoints > 127 mehr als nur ein Byte je Zeichen, das €-Zeichen z.B. benötigt 3 Bytes. Diese Bytes allein jedoch bringen den Browser nicht dazu, das €-Zeichen als Solches darzustellen, vielmehr muss dazu dem Browser auch die Kodierung mitgeteilt werden. Genau das ist die Zweckbestimmung der Klasse TextDecoder während die Klasse TextEncoder die Umkehrung beschreibt.

Die Kodierung ist eine Eigenschaft in document.charset

JavaScript betrachtet intern jede Zeichenkette als eine Solche mit einer ganz bestimmten Zeichenkodierung. Welche das ist, zeigt die Eigenschaft document.charset, auf der hier vorliegenden Seite ist document.charset = . Maßgeblich ist der vom Webserver gesendete Parameter Charset= im HTTP-Header Content-Type. Zur Veranschaulichung klicke hier womit ein anderer Charset proklamiert wird.

Bevor wir zu den Beispielen in Sachen UTF-8 kommen, erstellen wir uns eine eigene Klasse utf8. Diese Klasse kapselt Instanzen der Klassen TextDecoder() und TextEncoder(). Damit werden die beiden Methoden encode() und decode() zu Methoden der eigenen Klasse gemacht, diese Vorgehensweise wird auch als Delegierung bezeichnet.

// Eigene Klasse delegiert Methoden
// für TextEncoder() und TextDecoder()
function utf8(){
    this.enc = new TextEncoder();
    this.dec = new TextDecoder();
    this.encode = function(ustr){
        return this.enc.encode(ustr);
    };
    this.decode = function(uha){
        return this.dec.decode(uha);
    };
}

Wir können nun eine Instanz erstellen und beide Methoden vorteilhaft mit dieser einen Instanz aufrufen.

Beispiel1: Zeichenkette und ArrayBuffer

// Instanz der obenstehenden Klasse
var u = new utf8();
// 10 Zeichen
var uChars = "µ€äöüÄÖÜßß";

// Zeichenkette aus ArrayBuffer
var bb = new Blob([uChars]);
var fr = new FileReader();
fr.onload = function(){
    var uha = new Uint8Array(this.result);
    var ustr = u.decode(uha);
    console.log(ustr);
};
fr.readAsArrayBuffer(bb);

Erläuterungen: Die Zeichenkette in uChars wird JavaScript-intern als eine utf-8-kodierte Zeichenkette gehandelt. Wir erstellen einen Blob mit dieser Zeichenkette welcher diese genauso transportiert, also wäre dieselbe Zeichenkette aus einer Datei gelesen worden. Mit einer Instanz des FileReader wird dieser Blob nun genauso gelesen wie eine Datei die per FileApi reinkommt. Im Ergebnis dessen erhalten wir einen ArrayBuffer aus dem wir ein Uint8Array erstellen. Diese Uint8Array transportiert die Oktettenwertigkeiten der utf-8-kodierten Zeichenkette (10 Zeichen). Das Uint8Array hat also eine Länge von 21 Bytes. Unter der Anwendung von decode() wird aus dem Uint8Array die Zeichenkette als lesbare Zeichenkette utf-8-kodiert wiederhergestellt, was die Konsole zeigt.

Beispiel2: Base64 mit Zeichenkette

Mit btoa(uChars) erhalten wir eine Fehlermeldung: InvalidCharacterError: String contains an invalid character was daran lieg, daß die interne Zeichenkodierung eingeschaltet ist, die Funktion btoa() jedoch nach einer Bytesequenz (Binary) verlangt. Also wenden wir die Methode encode() an und erzeugen damit die Bytesequenz. Damit funktioniert Base64-Kodierung einwandfrei:

var bin = String.fromCharCode(...u.encode(uChars));
console.log( btoa(bin) );

Alternative zu TextDecoder: Prozentkodierung

Wir erzeugen aus obenstehende Zeichenkette einen Blob und lesen diesen als ArraBuffer. Aus diesem machen wir ein Uint8Array für die Bytewertigkeiten und gehen diese durch. Entsprechend der als deprecated eingestuften Funktion escape() werden nun alle Wertigkeiten die größer sind als 127 in einen prozentkodierten String umgeschrieben. Schließlich stellen wir aus diesem escaped String per decodeURIComponent() die utf-8-kodierte Zeichenkette wieder her die im DOM auch als Solche erkannt wird.

// Zeichenkette aus ArrayBuffer
var bb = new Blob([uChars]);
var fr = new FileReader();
fr.onload = function(){
    var uha = new Uint8Array(this.result);
    escaped_str = "";
    for(i = 0; i < uha.length; i++){
        ord = uha[i];
        escaped_str += ord > 127 ? "%"+ord.toString(16).toUpperCase() : String.fromCharCode(ord);
    }
    console.log(decodeURIComponent(escaped_str));

};
fr.readAsArrayBuffer(bb);


Datenschutzerklärung: Diese Seite dient rein privaten Zwecken. Auf den für diese Domäne installierten Seiten werden grundsätzlich keine personenbezogenen Daten erhoben. Das Loggen der Zugriffe mit Ihrer Remote Adresse erfolgt beim Provider soweit das technisch erforderlich ist. s​os­@rolf­rost.de