Conversión de matriz de bytes a cadena en javascript


80

¿Cómo convierto una matriz de bytes en una cadena?

He encontrado estas funciones que hacen lo contrario:

function string2Bin(s) {
    var b = new Array();
    var last = s.length;

    for (var i = 0; i < last; i++) {
        var d = s.charCodeAt(i);
        if (d < 128)
            b[i] = dec2Bin(d);
        else {
            var c = s.charAt(i);
            alert(c + ' is NOT an ASCII character');
            b[i] = -1;
        }
    }
    return b;
}

function dec2Bin(d) {
    var b = '';

    for (var i = 0; i < 8; i++) {
        b = (d%2) + b;
        d = Math.floor(d/2);
    }

    return b;
}

Pero, ¿cómo hago para que las funciones funcionen al revés?

Gracias.

Shao


¿Desea convertir una matriz de bytes en una cadena o una matriz de bits en una cadena?
mcandre

Consulte también la solución adecuada para la matriz utf8: Uint8Array to string en Javascript
Vadzim

Respuestas:


82

Necesita analizar cada octeto hasta el número y usar ese valor para obtener un carácter, algo como esto:

function bin2String(array) {
  var result = "";
  for (var i = 0; i < array.length; i++) {
    result += String.fromCharCode(parseInt(array[i], 2));
  }
  return result;
}

bin2String(["01100110", "01101111", "01101111"]); // "foo"

// Using your string2Bin function to test:
bin2String(string2Bin("hello world")) === "hello world";

Editar: Sí, su actual string2Binse puede escribir más brevemente:

function string2Bin(str) {
  var result = [];
  for (var i = 0; i < str.length; i++) {
    result.push(str.charCodeAt(i).toString(2));
  }
  return result;
}

Pero al mirar la documentación que vinculó, creo que el setBytesParametermétodo espera que la matriz de blobs contenga los números decimales, no una cadena de bits , por lo que podría escribir algo como esto:

function string2Bin(str) {
  var result = [];
  for (var i = 0; i < str.length; i++) {
    result.push(str.charCodeAt(i));
  }
  return result;
}

function bin2String(array) {
  return String.fromCharCode.apply(String, array);
}

string2Bin('foo'); // [102, 111, 111]
bin2String(string2Bin('foo')) === 'foo'; // true

Gracias por la respuesta súper rápida. Un par de preguntas ... 1) Su función bin2String es impresionante: solo 5 líneas de código. ¿Se puede cambiar la función string2bin para hacer uso de más funciones de Javascript para acortar la función y la subfunción? .....
user385579

1
2) La razón por la que necesito estas conversiones es porque estoy capturando una firma y tengo que convertirla para completar un campo BLOB en la base de datos. El problema es que, mientras estas 2 funciones funcionan, algo más va mal. Lo principal es que cuando recupero un BLOB de la base de datos, entra en un objeto de matriz de bytes. Sin embargo, cuando estoy escribiendo el BLOB en la base de datos después de ejecutarlo a través de la función original, no es un objeto de matriz de bytes. Esto podría ser lo que está causando el problema. ¿Algunas ideas?
user385579

dcx.sybase.com/index.html#1101en/ulmbus_en11/… Esta es la sintaxis que utilizo para configurar los datos.
user385579

4
String.fromCharCode.apply(String, array)no es seguro para cadenas muy largas en Safari. Hay un problema en JavaScriptCore que significa que las funciones no pueden tomar más de 65536 argumentos, o se lanzará un RangeError. También bloquea el navegador en matrices un poco más pequeñas que eso. Ver bugs.webkit.org/show_bug.cgi?id=80797
Mateo

4
Falla para caracteres utf-8 de varios bytes, es decir: bin2String([0xE2, 0x98, 0xB9])
Brad Kent

49

Simplemente applysu matriz de bytes a String.fromCharCode. Por ejemplo

String.fromCharCode.apply(null, [102, 111, 111]) es igual a 'foo'.

Advertencia: funciona para matrices de menos de 65535. Documentos de MDN aquí .


Esto ya ha sido demostrado por la respuesta aceptada hace 6 años.
Balthazar

2
aah, de hecho, me perdí esa línea. Básicamente, estaba buscando una frase breve y descarté esa respuesta larga y editada (tal vez demasiado apresurada).
Bogdan D

Oh, está bien, eso tiene sentido :)
Balthazar

11
Aunque es una repetición, su brevedad lo hace mejor que la respuesta aceptada.
Rich Apodaca

22

Pruebe la nueva API de codificación de texto:

// create an array view of some valid bytes
let bytesView = new Uint8Array([104, 101, 108, 108, 111]);

console.log(bytesView);

// convert bytes to string
// encoding can be specfied, defaults to utf-8 which is ascii.
let str = new TextDecoder().decode(bytesView); 

console.log(str);

// convert string to bytes
// encoding can be specfied, defaults to utf-8 which is ascii.
let bytes2 = new TextEncoder().encode(str);

// look, they're the same!
console.log(bytes2);
console.log(bytesView);


1
Desafortunadamente, IE no lo admite.
Soul_man

Si necesita compatibilidad con UTF-8 e IE, puede utilizar el polyfill FastestSmallestTextEncoderDecoder , recomendado por el sitio web de MDN .
Rosberg Linhares


8

Ese string2Bin se puede escribir de manera aún más sucinta y sin bucles, ¡para empezar!

function string2Bin ( str ) {
    return str.split("").map( function( val ) { 
        return val.charCodeAt( 0 ); 
    } );
}

1
Sería curioso ver si las llamadas de función agregadas ralentizan esto.
jocull

36
Todavía tiene un bucle, simplemente está oculto dentro de map ().
Johannes Lumpe

4

Creo que esto sería más eficiente:

function toBinString (arr) {
    var uarr = new Uint8Array(arr.map(function(x){return parseInt(x,2)}));
    var strings = [], chunksize = 0xffff;
    // There is a maximum stack size. We cannot call String.fromCharCode with as many arguments as we want
    for (var i=0; i*chunksize < uarr.length; i++){
        strings.push(String.fromCharCode.apply(null, uarr.subarray(i*chunksize, (i+1)*chunksize)));
    }
    return strings.join('');
}

4

Incluso si llego un poco tarde, pensé que sería interesante para los futuros usuarios compartir algunas implementaciones de una sola línea que hice con ES6.

Una cosa que considero importante dependiendo de su entorno y / y lo que hará con los datos es preservar el valor de byte completo. Por ejemplo, (5).toString(2)le dará 101, pero la conversión binaria completa es en realidad 00000101, y es por eso que es posible que deba crear una leftPadimplementación para completar el byte de cadena con ceros a la izquierda. Pero es posible que no lo necesite en absoluto, como demostraron otras respuestas.

Si ejecuta el siguiente fragmento de código, verá que la primera salida es la conversión de la abccadena en una matriz de bytes y, justo después, la transformación de dicha matriz en su cadena correspondiente.

// For each byte in our array, retrieve the char code value of the binary value
const binArrayToString = array => array.map(byte => String.fromCharCode(parseInt(byte, 2))).join('')

// Basic left pad implementation to ensure string is on 8 bits
const leftPad = str => str.length < 8 ? (Array(8).join('0') + str).slice(-8) : str

// For each char of the string, get the int code and convert it to binary. Ensure 8 bits.
const stringToBinArray = str => str.split('').map(c => leftPad(c.charCodeAt().toString(2)))

const array = stringToBinArray('abc')

console.log(array)
console.log(binArrayToString(array))


3

Cadena a matriz de bytes: "FooBar".split('').map(c => c.charCodeAt(0));

Matriz de bytes a cadena: [102, 111, 111, 98, 97, 114].map(c => String.fromCharCode(c)).join('');


tenga cuidado, esto no es compatible con IE.
tedebus

1

Demasiado tarde para responder, pero si su entrada está en forma de bytes ASCII, entonces puede probar esta solución:

function convertArrToString(rArr){
 //Step 1: Convert each element to character
 let tmpArr = new Array();
 rArr.forEach(function(element,index){
    tmpArr.push(String.fromCharCode(element));
});
//Step 2: Return the string by joining the elements
return(tmpArr.join(""));
}

function convertArrToHexNumber(rArr){
  return(parseInt(convertArrToString(rArr),16));
}

1

Si está utilizando node.js , puede hacer esto:

yourByteArray.toString('base64');

0

No encontré ninguna solución que funcionara con caracteres UTF-8. String.fromCharCodees bueno hasta que encuentre el carácter de 2 bytes.

Por ejemplo, Hüser vendrá como[0x44,0x61,0x6e,0x69,0x65,0x6c,0x61,0x20,0x48,0xc3,0xbc,0x73,0x65,0x72]

Pero si lo revisa,String.fromCharCode tendrá Hüser, ya que cada byte se convertirá en un carácter por separado.

Solución

Actualmente estoy usando la siguiente solución:

function pad(n) { return (n.length < 2 ? '0' + n : n); }
function decodeUtf8(data) {
  return decodeURIComponent(
    data.map(byte => ('%' + pad(byte.toString(16)))).join('')
  );
}

0

Tenía algunas matrices de bytes descifradas con caracteres de relleno y otras cosas que no necesitaba, así que hice esto (probablemente no sea perfecto, pero funciona para mi uso limitado)

var junk = String.fromCharCode.apply(null, res).split('').map(char => char.charCodeAt(0) <= 127 && char.charCodeAt(0) >= 32 ? char : '').join('');

0

Si su matriz está codificada en UTF-8 y no puede usar la API TextDecoder porque no es compatible con IE :

  1. Puede utilizar el polyfill FastestSmallestTextEncoderDecoder recomendado por el sitio web de Mozilla Developer Network ;
  2. Puede utilizar esta función que también se proporciona en el sitio web de MDN :

function utf8ArrayToString(aBytes) {
    var sView = "";
    
    for (var nPart, nLen = aBytes.length, nIdx = 0; nIdx < nLen; nIdx++) {
        nPart = aBytes[nIdx];
        
        sView += String.fromCharCode(
            nPart > 251 && nPart < 254 && nIdx + 5 < nLen ? /* six bytes */
                /* (nPart - 252 << 30) may be not so safe in ECMAScript! So...: */
                (nPart - 252) * 1073741824 + (aBytes[++nIdx] - 128 << 24) + (aBytes[++nIdx] - 128 << 18) + (aBytes[++nIdx] - 128 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
            : nPart > 247 && nPart < 252 && nIdx + 4 < nLen ? /* five bytes */
                (nPart - 248 << 24) + (aBytes[++nIdx] - 128 << 18) + (aBytes[++nIdx] - 128 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
            : nPart > 239 && nPart < 248 && nIdx + 3 < nLen ? /* four bytes */
                (nPart - 240 << 18) + (aBytes[++nIdx] - 128 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
            : nPart > 223 && nPart < 240 && nIdx + 2 < nLen ? /* three bytes */
                (nPart - 224 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
            : nPart > 191 && nPart < 224 && nIdx + 1 < nLen ? /* two bytes */
                (nPart - 192 << 6) + aBytes[++nIdx] - 128
            : /* nPart < 127 ? */ /* one byte */
                nPart
        );
    }
    
    return sView;
}

let str = utf8ArrayToString([50,72,226,130,130,32,43,32,79,226,130,130,32,226,135,140,32,50,72,226,130,130,79]);

// Must show 2H₂ + O₂ ⇌ 2H₂O
console.log(str);


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.