web-dev-qa-db-fra.com

Conversion entre UTF-8 ArrayBuffer et String

J'ai une ArrayBuffer qui contient une chaîne encodée en UTF-8 et je ne trouve pas de méthode standard pour convertir une telle ArrayBuffer en une JS String (qui, à ce que je comprends, est encodée en UTF-16).

J'ai vu ce code à de nombreux endroits, mais je ne vois pas comment cela fonctionnerait avec les points de code UTF-8 dont la longueur est supérieure à 1 octet.

return String.fromCharCode.apply(null, new Uint8Array(data));

De même, je ne trouve pas de méthode standard pour convertir une String en une UTF-8 encodée ArrayBuffer.

50
Tom Leese
function stringToUint(string) {
    var string = btoa(unescape(encodeURIComponent(string))),
        charList = string.split(''),
        uintArray = [];
    for (var i = 0; i < charList.length; i++) {
        uintArray.Push(charList[i].charCodeAt(0));
    }
    return new Uint8Array(uintArray);
}

function uintToString(uintArray) {
    var encodedString = String.fromCharCode.apply(null, uintArray),
        decodedString = decodeURIComponent(escape(atob(encodedString)));
    return decodedString;
}

J'ai fait, avec l'aide d'Internet, ces petites fonctions, elles devraient résoudre vos problèmes! Voici le travail JSFiddle .

MODIFIER:

Étant donné que la source de Uint8Array est externe et que vous ne pouvez pas utiliser atob, vous devez simplement le supprimer ( working fiddle ):

function uintToString(uintArray) {
    var encodedString = String.fromCharCode.apply(null, uintArray),
        decodedString = decodeURIComponent(escape(encodedString));
    return decodedString;
}
36

Utiliser TextEncoder et TextDecoder

var uint8array = new TextEncoder("utf-8").encode("Plain Text");
var string = new TextDecoder().decode(uint8array);
console.log(uint8array ,string )
23
PPB

Cela devrait fonctionner:

// http://www.onicos.com/staff/iz/amuse/javascript/expert/utf.txt

/* utf.js - UTF-8 <=> UTF-16 convertion
 *
 * Copyright (C) 1999 Masanao Izumo <[email protected]>
 * Version: 1.0
 * LastModified: Dec 25 1999
 * This library is free.  You can redistribute it and/or modify it.
 */

function Utf8ArrayToStr(array) {
  var out, i, len, c;
  var char2, char3;

  out = "";
  len = array.length;
  i = 0;
  while (i < len) {
    c = array[i++];
    switch (c >> 4)
    { 
      case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
        // 0xxxxxxx
        out += String.fromCharCode(c);
        break;
      case 12: case 13:
        // 110x xxxx   10xx xxxx
        char2 = array[i++];
        out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
        break;
      case 14:
        // 1110 xxxx  10xx xxxx  10xx xxxx
        char2 = array[i++];
        char3 = array[i++];
        out += String.fromCharCode(((c & 0x0F) << 12) |
                                   ((char2 & 0x3F) << 6) |
                                   ((char3 & 0x3F) << 0));
        break;
    }
  }    
  return out;
}

Elle est un peu plus propre que les autres solutions car elle n’utilise pas de piratage informatique et ne dépend pas non plus des fonctions JS du navigateur, par exemple. fonctionne également dans d'autres environnements JS.

Découvrez la démo JSFiddle .

Voir également les questions connexes: ici , ici

22
Albert

Il y a un polyfill pour Encodage sur Github: text-encoding . C'est facile pour Node ou le navigateur, et le fichier Lisez-moi conseille ce qui suit:

var uint8array = TextEncoder(encoding).encode(string);
var string = TextDecoder(encoding).decode(uint8array);

Si je me souviens bien, 'utf-8' est la encoding dont vous avez besoin, et vous devrez bien sûr envelopper votre tampon:

var uint8array = new Uint8Array(utf8buffer);

J'espère que cela fonctionne aussi bien pour vous que pour moi.

17
popham

Si vous faites cela dans le navigateur, il n’existe pas de bibliothèques de codage de caractères intégrées, mais vous pouvez obtenirby avec:

function pad(n) {
    return n.length < 2 ? "0" + n : n;
}

var array = new Uint8Array(data);
var str = "";
for( var i = 0, len = array.length; i < len; ++i ) {
    str += ( "%" + pad(array[i].toString(16)))
}

str = decodeURIComponent(str);

Voici une démo qui décode une unité UTF-8 de 3 octets: http://jsfiddle.net/Z9pQE/

9
Esailija

Les méthodes readAsArrayBuffer et readAsText d'un objet FileReader convertissent un objet Blob en un objet ArrayBuffer ou en une chaîne asynchrone DOMString.

Un type d'objet Blob peut être créé à partir d'un tableau de texte brut ou d'octets, par exemple.

let blob = new Blob([text], { type: "text/plain" });

let reader = new FileReader();
reader.onload = event =>
{
    let buffer = event.target.result;
};
reader.readAsArrayBuffer(blob);

Je pense qu'il est préférable de résumer cela dans une promesse:

function textToByteArray(text)
{
    let blob = new Blob([text], { type: "text/plain" });
    let reader = new FileReader();
    let done = function() { };

    reader.onload = event =>
    {
        done(new Uint8Array(event.target.result));
    };
    reader.readAsArrayBuffer(blob);

    return { done: function(callback) { done = callback; } }
}

function byteArrayToText(bytes, encoding)
{
    let blob = new Blob([bytes], { type: "application/octet-stream" });
    let reader = new FileReader();
    let done = function() { };

    reader.onload = event =>
    {
        done(event.target.result);
    };

    if(encoding) { reader.readAsText(blob, encoding); } else { reader.readAsText(blob); }

    return { done: function(callback) { done = callback; } }
}

let text = "\uD83D\uDCA9 = \u2661";
textToByteArray(text).done(bytes =>
{
    console.log(bytes);
    byteArrayToText(bytes, 'UTF-8').done(text => 
    {
        console.log(text); // ???? = ♡
    });
});
2
Martin Wantke

Le principal problème des programmeurs cherchant à convertir un tableau d'octets en chaîne est le codage UTF-8 (compression) des caractères unicode. Ce code vous aidera:

var getString = function (strBytes) {

    var MAX_SIZE = 0x4000;
    var codeUnits = [];
    var highSurrogate;
    var lowSurrogate;
    var index = -1;

    var result = '';

    while (++index < strBytes.length) {
        var codePoint = Number(strBytes[index]);

        if (codePoint === (codePoint & 0x7F)) {

        } else if (0xF0 === (codePoint & 0xF0)) {
            codePoint ^= 0xF0;
            codePoint = (codePoint << 6) | (strBytes[++index] ^ 0x80);
            codePoint = (codePoint << 6) | (strBytes[++index] ^ 0x80);
            codePoint = (codePoint << 6) | (strBytes[++index] ^ 0x80);
        } else if (0xE0 === (codePoint & 0xE0)) {
            codePoint ^= 0xE0;
            codePoint = (codePoint << 6) | (strBytes[++index] ^ 0x80);
            codePoint = (codePoint << 6) | (strBytes[++index] ^ 0x80);
        } else if (0xC0 === (codePoint & 0xC0)) {
            codePoint ^= 0xC0;
            codePoint = (codePoint << 6) | (strBytes[++index] ^ 0x80);
        }

        if (!isFinite(codePoint) || codePoint < 0 || codePoint > 0x10FFFF || Math.floor(codePoint) != codePoint)
            throw RangeError('Invalid code point: ' + codePoint);

        if (codePoint <= 0xFFFF)
            codeUnits.Push(codePoint);
        else {
            codePoint -= 0x10000;
            highSurrogate = (codePoint >> 10) | 0xD800;
            lowSurrogate = (codePoint % 0x400) | 0xDC00;
            codeUnits.Push(highSurrogate, lowSurrogate);
        }
        if (index + 1 == strBytes.length || codeUnits.length > MAX_SIZE) {
            result += String.fromCharCode.apply(null, codeUnits);
            codeUnits.length = 0;
        }
    }

    return result;
}

Bonne chance !

0
konak

Pour ceux qui travaillent dans Node.js> = 0.1.99

Node.js propose un module intégré appelé StringDecoder qui est expressément conçu pour décoder les tampons de plusieurs octets en chaînes.

https://nodejs.org/api/string_decoder.html

À partir du lien ci-dessus:

Le module string_decoder fournit une API permettant de décoder des objets tampon en chaînes de manière à préserver les caractères codés UTF-8 et UTF-16 codés sur plusieurs octets.

Exemple (emprunté aux documents ci-dessus):


const { StringDecoder } = require('string_decoder');
const decoder = new StringDecoder('utf8');

const cent = Buffer.from([0xC2, 0xA2]);
console.log(decoder.write(cent)); // ¢

const euro = Buffer.from([0xE2, 0x82, 0xAC]);
console.log(decoder.write(euro)); // €

0
Justin Beaudry