javascript - Conversión entre UTF-8 ArrayBuffer y String
byte to blob javascript (8)
El principal problema de los programadores que buscan la conversión de una matriz de bytes en una cadena es la codificación UTF-8 (compresión) de caracteres Unicode. Este código te ayudará a:
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;
}
Todo lo mejor !
Tengo un ArrayBuffer
que contiene una cadena codificada usando UTF-8 y no puedo encontrar una forma estándar de convertir dicho ArrayBuffer
en una String
JS (que entiendo está codificada usando UTF-16).
He visto este código en numerosos lugares, pero no veo cómo funcionaría con los puntos de código UTF-8 que son más largos que 1 byte.
return String.fromCharCode.apply(null, new Uint8Array(data));
Del mismo modo, no puedo encontrar una forma estándar de convertir de un String
a un ArrayBuffer
codificado en UTF-8.
Enfrenté el mismo problema pero necesitaba poder analizar / escribir datos codificados UTF8 progresivamente. Aquí hay una lib que acabo de hacer para enfrentar este problema https://github.com/nfroidure/UTF8.js .
Editar: Parece que Mozilla está cocinando algo para nosotros: StringView ( https://developer.mozilla.org/en-US/docs/Code_snippets/StringView?redirectlocale=en-US&redirectslug=Web%2FJavaScript%2FTyped_arrays%2FStringView#encoding_values )
Esto debería funcionar:
// 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;
}
Es algo más limpio que las otras soluciones porque no utiliza ningún hackeo ni depende de las funciones del navegador JS, por ejemplo, funciona también en otros entornos JS.
Mira la demostración de JSFiddle .
Hay un polyfill para Encoding over en Github: text-encoding . Es fácil para Node o el navegador, y el archivo Léame aconseja lo siguiente:
var uint8array = TextEncoder(encoding).encode(string);
var string = TextDecoder(encoding).decode(uint8array);
Si no recuerdo ''utf-8''
, ''utf-8''
es la encoding
que necesitas y, por supuesto, tendrás que ajustar tu buffer:
var uint8array = new Uint8Array(utf8buffer);
Espero que funcione tan bien para ti como lo tiene para mí.
Los métodos readAsArrayBuffer y readAsText de un objeto FileReader convierten un objeto Blob en ArrayBuffer o en DOMString asincrónico.
Por ejemplo, se puede crear un tipo de objeto Blob a partir de un conjunto de texto sin formato o de bytes.
let blob = new Blob([text], { type: "text/plain" });
let reader = new FileReader();
reader.onload = event =>
{
let buffer = event.target.result;
};
reader.readAsArrayBuffer(blob);
Creo que es mejor empacar esto en una promesa:
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); // 💩 = ♡
});
});
Si está haciendo esto en el navegador, no hay bibliotecas de codificación de caracteres incorporadas, pero puede hacerlo con:
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);
Aquí hay una demostración que decodifica una unidad UTF-8 de 3 bytes: http://jsfiddle.net/Z9pQE/
Usando TextEncoder y TextDecoder
var uint8array = new TextEncoder("utf-8").encode("Plain Text");
var string = new TextDecoder().decode(uint8array);
console.log(uint8array ,string )
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;
}
He hecho, con alguna ayuda de internet, estas pequeñas funciones, ¡deberían resolver tus problemas! Aquí está el JSFiddle de trabajo .
EDITAR :
Como la fuente de Uint8Array es externa y no puedes usar atob
, solo necesitas quitarla ( violín de trabajo ):
function uintToString(uintArray) {
var encodedString = String.fromCharCode.apply(null, uintArray),
decodedString = decodeURIComponent(escape(encodedString));
return decodedString;
}