web-dev-qa-db-fra.com

Comment convertir une chaîne UTF8 en tableau d'octets?

Le .charCodeAt La fonction retourne avec le code unicode du caractère. Mais je voudrais plutôt obtenir le tableau d'octets. Je sais que si le code de caractère est supérieur à 127, le caractère est stocké dans deux octets ou plus.

var arr=[];
for(var i=0; i<str.length; i++) {
    arr.Push(str.charCodeAt(i))
}
40
don kaka

La logique de codage Unicode en UTF-8 est la suivante:

  • Vous pouvez utiliser jusqu'à 4 octets par caractère. Le plus petit nombre d'octets possible est utilisé.
  • Les caractères jusqu'à U + 007F sont codés avec un seul octet.
  • Pour les séquences multi-octets, le nombre de bits 1 en tête dans le premier octet indique le nombre d'octets du caractère. Le reste des bits du premier octet peut être utilisé pour coder des bits du caractère.
  • Les octets de continuation commencent par 10 et les 6 autres bits encodent les bits du caractère.

Voici une fonction que j'ai écrite il y a longtemps pour encoder une chaîne JavaScript UTF-16 en UTF-8:

function toUTF8Array(str) {
    var utf8 = [];
    for (var i=0; i < str.length; i++) {
        var charcode = str.charCodeAt(i);
        if (charcode < 0x80) utf8.Push(charcode);
        else if (charcode < 0x800) {
            utf8.Push(0xc0 | (charcode >> 6), 
                      0x80 | (charcode & 0x3f));
        }
        else if (charcode < 0xd800 || charcode >= 0xe000) {
            utf8.Push(0xe0 | (charcode >> 12), 
                      0x80 | ((charcode>>6) & 0x3f), 
                      0x80 | (charcode & 0x3f));
        }
        // surrogate pair
        else {
            i++;
            // UTF-16 encodes 0x10000-0x10FFFF by
            // subtracting 0x10000 and splitting the
            // 20 bits of 0x0-0xFFFFF into two halves
            charcode = 0x10000 + (((charcode & 0x3ff)<<10)
                      | (str.charCodeAt(i) & 0x3ff));
            utf8.Push(0xf0 | (charcode >>18), 
                      0x80 | ((charcode>>12) & 0x3f), 
                      0x80 | ((charcode>>6) & 0x3f), 
                      0x80 | (charcode & 0x3f));
        }
    }
    return utf8;
}
57
Joni

JavaScript Strings are stocké dans UTF-16 . Pour obtenir UTF-8, vous devrez convertir vous-même le String.

Une solution consiste à mélanger encodeURIComponent() , ce qui générera un octet UTF-8 codé en URL, avec unescape , comme mentionné sur ecmanaut .

var utf8 = unescape(encodeURIComponent(str));

var arr = [];
for (var i = 0; i < utf8.length; i++) {
    arr.Push(utf8.charCodeAt(i));
}
35
Jonathan Lonowski

La nouvelle API de codage semble vous permettre à la fois de coder et de décoder UTF-8 facilement (à l'aide de tableaux typés):

var encoded = new TextEncoder("utf-8").encode("Γεια σου κόσμε");
var decoded = new TextDecoder("utf-8").decode(encoded);

console.log(encoded, decoded);

Support du navigateur c'est pas mal , et il y a un polyfill qui devrait fonctionner dans IE11 et les versions antérieures d'Edge.

L'API prend également en charge de nombreux encodages différents. Je l'ai utilisé pour décoder/encoder du texte japonais (Shift-JIS) avec ceci:

new TextDecoder("shift-jis").decode(new Uint8Array(textbuffer))
9
bryc

La bibliothèque Google Closure possède des fonctions permettant de convertir en/à partir des tableaux UTF-8 et byte. Si vous ne voulez pas utiliser toute la bibliothèque, vous pouvez copier les fonctions de ici . Pour être complet, le code à convertir en chaîne en un tableau d'octets UTF-8 est:

goog.crypt.stringToUtf8ByteArray = function(str) {
  // TODO(user): Use native implementations if/when available
  var out = [], p = 0;
  for (var i = 0; i < str.length; i++) {
    var c = str.charCodeAt(i);
    if (c < 128) {
      out[p++] = c;
    } else if (c < 2048) {
      out[p++] = (c >> 6) | 192;
      out[p++] = (c & 63) | 128;
    } else if (
        ((c & 0xFC00) == 0xD800) && (i + 1) < str.length &&
        ((str.charCodeAt(i + 1) & 0xFC00) == 0xDC00)) {
      // Surrogate Pair
      c = 0x10000 + ((c & 0x03FF) << 10) + (str.charCodeAt(++i) & 0x03FF);
      out[p++] = (c >> 18) | 240;
      out[p++] = ((c >> 12) & 63) | 128;
      out[p++] = ((c >> 6) & 63) | 128;
      out[p++] = (c & 63) | 128;
    } else {
      out[p++] = (c >> 12) | 224;
      out[p++] = ((c >> 6) & 63) | 128;
      out[p++] = (c & 63) | 128;
    }
  }
  return out;
};
8
optevo

En supposant que la question concerne une chaîne DOMString en entrée et que le but est d'obtenir un tableau, qui, interprété comme une chaîne (écrite dans un fichier sur le disque, par exemple), serait encodé en UTF-8:

Maintenant que presque tous les navigateurs modernes supporte Typed Arrays , il serait honteux que cette approche ne soit pas listée:

  • Selon le W3C , les logiciels prenant en charge l’API de fichier doivent accepter DOMString s dans leur Constructeur de blob (voir aussi: Encodage de chaîne lors de la construction d'un blob) )
  • Les blobs peuvent être convertis en un ArrayBuffer à l’aide de la fonction .readAsArrayBuffer() d’un lecteur de fichiers
  • En utilisant un DataView ou en construisant un tableau typé avec le tampon lu par le Lecteur de fichiers, on peut accéder à tous les octets de l'ArrayBuffer

Exemple:

// Create a Blob with an Euro-char (U+20AC)
var b = new Blob(['€']);
var fr = new FileReader();

fr.onload = function() {
    ua = new Uint8Array(fr.result);
    // This will log "3|226|130|172"
    //                  E2  82  AC
    // In UTF-16, it would be only 2 bytes long
    console.log(
        fr.result.byteLength + '|' + 
        ua[0]  + '|' + 
        ua[1] + '|' + 
        ua[2] + ''
    );
};
fr.readAsArrayBuffer(b);

Jouez avec ça sur JSFiddle . Je n'ai pas encore analysé ce point de vue, mais je peux imaginer que cela soit efficace pour les grandes chaînes DOMString.

6
Rainer Rillke

Vous pouvez enregistrer une chaîne brute telle quelle en utilisant FileReader.

Enregistrez la chaîne dans un blob et appelez readAsArrayBuffer () . Ensuite, l'événement onload génère un tampon de matrice pouvant être converti en Uint8Array. Malheureusement, cet appel est asynchrone.

Cette petite fonction vous aidera à:

function stringToBytes(str)
{
    let reader = new FileReader();
    let done = () => {};

    reader.onload = event =>
    {
        done(new Uint8Array(event.target.result), str);
    };
    reader.readAsArrayBuffer(new Blob([str], { type: "application/octet-stream" }));

    return { done: callback => { done = callback; } };
}

Appelez ça comme ça:

stringToBytes("\u{1f4a9}").done(bytes =>
{
    console.log(bytes);
});

sortie:[240, 159, 146, 169]

explication:

JavaScript utilise UTF-16 et des paires de substitution pour stocker des caractères Unicode en mémoire. Pour enregistrer un caractère unicode dans des flux d'octets binaires bruts, un codage est nécessaire. UTF-8 est généralement utilisé dans ce cas. Si vous n’utilisez pas d’encodage, vous ne pouvez pas sauvegarder de caractères Unicode, il suffit de ASCII jusqu’à 0x7f.

FileReader.readAsArrayBuffer () utilise UTF-8.

2
Martin Wantke

J'utilisais solution de Joni et cela a bien fonctionné, mais celui-ci est beaucoup plus court.

Cela a été inspiré par la fonction atobUTF16 () de la solution n ° 3 de discussion Unicode en Base64 de Mozilla

function convertStringToUTF8ByteArray(str) {
    let binaryArray = new Uint8Array(str.length)
    Array.prototype.forEach.call(binaryArray, function (el, idx, arr) { arr[idx] = str.charCodeAt(idx) })
    return binaryArray
}
1
jk7