¿Cómo puedo convertir una cadena en bytearray usando JavaScript? La salida debe ser equivalente al código C # siguiente.
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] bytes = encoding.GetBytes(AnyString);
Como UnicodeEncoding es por defecto UTF-16 con Little-Endianness.
Editar: Tengo el requisito de hacer coincidir el lado del cliente generado por bytearray con el generado en el lado del servidor usando el código C # anterior.
javascript
shas
fuente
fuente
Respuestas:
En C # ejecutando esto
UnicodeEncoding encoding = new UnicodeEncoding(); byte[] bytes = encoding.GetBytes("Hello");
Creará una matriz con
72,0,101,0,108,0,108,0,111,0
Para un carácter cuyo código sea mayor que 255, se verá así
Si desea un comportamiento muy similar en JavaScript, puede hacer esto (v2 es una solución un poco más robusta, mientras que la versión original solo funcionará para 0x00 ~ 0xff)
var str = "Hello竜"; var bytes = []; // char codes var bytesv2 = []; // char codes for (var i = 0; i < str.length; ++i) { var code = str.charCodeAt(i); bytes = bytes.concat([code]); bytesv2 = bytesv2.concat([code & 0xff, code / 256 >>> 0]); } // 72, 101, 108, 108, 111, 31452 console.log('bytes', bytes.join(', ')); // 72, 0, 101, 0, 108, 0, 108, 0, 111, 0, 220, 122 console.log('bytesv2', bytesv2.join(', '));
fuente
Si está buscando una solución que funcione en node.js, puede usar esto:
var myBuffer = []; var str = 'Stack Overflow'; var buffer = new Buffer(str, 'utf16le'); for (var i = 0; i < buffer.length; i++) { myBuffer.push(buffer[i]); } console.log(myBuffer);
fuente
Supongo que C # y Java producen matrices de bytes iguales. Si tiene caracteres que no son ASCII, no es suficiente agregar un 0 adicional. Mi ejemplo contiene algunos caracteres especiales:
var str = "Hell ö € Ω 𝄞"; var bytes = []; var charCode; for (var i = 0; i < str.length; ++i) { charCode = str.charCodeAt(i); bytes.push((charCode & 0xFF00) >> 8); bytes.push(charCode & 0xFF); } alert(bytes.join(' ')); // 0 72 0 101 0 108 0 108 0 32 0 246 0 32 32 172 0 32 3 169 0 32 216 52 221 30
No sé si C # coloca BOM (Byte Order Marks), pero si usa UTF-16, Java
String.getBytes
agrega los siguientes bytes: 254255.String s = "Hell ö € Ω "; // now add a character outside the BMP (Basic Multilingual Plane) // we take the violin-symbol (U+1D11E) MUSICAL SYMBOL G CLEF s += new String(Character.toChars(0x1D11E)); // surrogate codepoints are: d834, dd1e, so one could also write "\ud834\udd1e" byte[] bytes = s.getBytes("UTF-16"); for (byte aByte : bytes) { System.out.print((0xFF & aByte) + " "); } // 254 255 0 72 0 101 0 108 0 108 0 32 0 246 0 32 32 172 0 32 3 169 0 32 216 52 221 30
Editar:
Se agregó un carácter especial (U + 1D11E) SÍMBOLO MUSICAL G CLEF (fuera de BPM, por lo que no solo toma 2 bytes en UTF-16, sino 4.
Las versiones actuales de JavaScript utilizan "UCS-2" internamente, por lo que este símbolo ocupa el espacio de 2 caracteres normales.
No estoy seguro, pero al usar
charCodeAt
parece que obtenemos exactamente los puntos de código sustitutos que también se usan en UTF-16, por lo que los caracteres que no son BPM se manejan correctamente.Este problema no es absolutamente trivial. Puede depender de las versiones y motores de JavaScript utilizados. Entonces, si desea soluciones confiables, debería echar un vistazo a:
fuente
charCodeAt
devuelve una unidad de código UTF-16, en el rango 0-65535. Los caracteres fuera del rango de 2 bytes se representan como pares sustitutos, al igual que en UTF-16. (Por cierto, esto es cierto para las cadenas en varios otros lenguajes, incluidos Java y C #.)(charCode & 0xFF00) >> 8
es redundante, no es necesario enmascararlo antes de cambiar.La forma más fácil en 2018 debería ser TextEncoder, pero el elemento devuelto no es una matriz de bytes, es Uint8Array. (Y no todos los navegadores lo admiten)
let utf8Encode = new TextEncoder(); utf8Encode.encode("eee") > Uint8Array [ 101, 101, 101 ]
fuente
new TextDecoder().decode(new TextEncoder().encode(str)) == str
.TextEncoder
: caniuseMatriz de bytes UTF-16
JavaScript codifica cadenas como UTF-16 , al igual que C #
UnicodeEncoding
, por lo que las matrices de bytes deben coincidir exactamente usandocharCodeAt()
y dividiendo cada par de bytes devueltos en 2 bytes separados, como en:function strToUtf16Bytes(str) { const bytes = []; for (ii = 0; ii < str.length; ii++) { const code = str.charCodeAt(ii); // x00-xFFFF bytes.push(code & 255, code >> 8); // low, high } return bytes; }
Por ejemplo:
strToUtf16Bytes('🌵'); // [ 60, 216, 53, 223 ]
Sin embargo, si desea obtener una matriz de bytes UTF-8, debe transcodificar los bytes.
Matriz de bytes UTF-8
La solución no parece trivial, pero utilicé el siguiente código en un entorno de producción de alto tráfico con gran éxito ( fuente original ).
Además, para el lector interesado, publiqué mis ayudantes Unicode que me ayudan a trabajar con longitudes de cadenas informadas por otros lenguajes como PHP.
/** * Convert a string to a unicode byte array * @param {string} str * @return {Array} of bytes */ export function strToUtf8Bytes(str) { const utf8 = []; for (let ii = 0; ii < str.length; ii++) { let charCode = str.charCodeAt(ii); 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)); } else { ii++; // Surrogate pair: // 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(ii) & 0x3ff)); utf8.push( 0xf0 | (charCode >> 18), 0x80 | ((charCode >> 12) & 0x3f), 0x80 | ((charCode >> 6) & 0x3f), 0x80 | (charCode & 0x3f), ); } } return utf8; }
fuente
Inspirado en la respuesta de @ hgoebl. Su código es para UTF-16 y necesitaba algo para US-ASCII. Entonces, aquí hay una respuesta más completa que cubre US-ASCII, UTF-16 y UTF-32.
/**@returns {Array} bytes of US-ASCII*/ function stringToAsciiByteArray(str) { var bytes = []; for (var i = 0; i < str.length; ++i) { var charCode = str.charCodeAt(i); if (charCode > 0xFF) // char > 1 byte since charCodeAt returns the UTF-16 value { throw new Error('Character ' + String.fromCharCode(charCode) + ' can\'t be represented by a US-ASCII byte.'); } bytes.push(charCode); } return bytes; } /**@returns {Array} bytes of UTF-16 Big Endian without BOM*/ function stringToUtf16ByteArray(str) { var bytes = []; //currently the function returns without BOM. Uncomment the next line to change that. //bytes.push(254, 255); //Big Endian Byte Order Marks for (var i = 0; i < str.length; ++i) { var charCode = str.charCodeAt(i); //char > 2 bytes is impossible since charCodeAt can only return 2 bytes bytes.push((charCode & 0xFF00) >>> 8); //high byte (might be 0) bytes.push(charCode & 0xFF); //low byte } return bytes; } /**@returns {Array} bytes of UTF-32 Big Endian without BOM*/ function stringToUtf32ByteArray(str) { var bytes = []; //currently the function returns without BOM. Uncomment the next line to change that. //bytes.push(0, 0, 254, 255); //Big Endian Byte Order Marks for (var i = 0; i < str.length; i+=2) { var charPoint = str.codePointAt(i); //char > 4 bytes is impossible since codePointAt can only return 4 bytes bytes.push((charPoint & 0xFF000000) >>> 24); bytes.push((charPoint & 0xFF0000) >>> 16); bytes.push((charPoint & 0xFF00) >>> 8); bytes.push(charPoint & 0xFF); } return bytes; }
UTF-8 es de longitud variable y no está incluido porque tendría que escribir la codificación yo mismo. UTF-8 y UTF-16 son de longitud variable. UTF-8, UTF-16 y UTF-32 tienen un número mínimo de bits como lo indica su nombre. Si un carácter UTF-32 tiene un punto de código de 65, significa que hay 3 ceros a la izquierda. Pero el mismo código para UTF-16 solo tiene 1 0 a la izquierda. Por otro lado, US-ASCII tiene un ancho fijo de 8 bits, lo que significa que se puede traducir directamente a bytes.
String.prototype.charCodeAt
devuelve un número máximo de 2 bytes y coincide exactamente con UTF-16. Sin embargo,String.prototype.codePointAt
se necesita UTF-32, que es parte de la propuesta ECMAScript 6 (Harmony). Debido a que charCodeAt devuelve 2 bytes, que son más caracteres posibles de los que puede representar US-ASCII, la funciónstringToAsciiByteArray
arrojará en tales casos en lugar de dividir el carácter por la mitad y tomar uno o ambos bytes.Tenga en cuenta que esta respuesta no es trivial porque la codificación de caracteres no es trivial. El tipo de matriz de bytes que desee dependerá de la codificación de caracteres que desee que representen esos bytes.
javascript tiene la opción de usar internamente UTF-16 o UCS-2, pero como tiene métodos que actúan como si fuera UTF-16, no veo por qué cualquier navegador usaría UCS-2. Ver también: https://mathiasbynens.be/notes/javascript-encoding
Sí, sé que la pregunta tiene 4 años, pero necesitaba esta respuesta para mí.
fuente
'02'
son[ 48, 0, 50, 0 ]
dondestringToUtf16ByteArray
regresa su función[ 0, 48, 0, 50 ]
. cual es la correcta?Como no puedo comentar la respuesta, me basaría en la respuesta de Jin Izzraeel.
diciendo que puede usar esto si desea usar un búfer Node.js en su navegador.
https://github.com/feross/buffer
Por lo tanto, la objeción de Tom Stickel no es válida y la respuesta es de hecho una respuesta válida.
fuente
String.prototype.encodeHex = function () { return this.split('').map(e => e.charCodeAt()) }; String.prototype.decodeHex = function () { return this.map(e => String.fromCharCode(e)).join('') };
fuente
encodeHex
devolverá una matriz de números de 16 bits, no bytes.La mejor solución que se me ocurrió en el acto (aunque lo más probable es que sea cruda) sería:
String.prototype.getBytes = function() { var bytes = []; for (var i = 0; i < this.length; i++) { var charCode = this.charCodeAt(i); var cLen = Math.ceil(Math.log(charCode)/Math.log(256)); for (var j = 0; j < cLen; j++) { bytes.push((charCode << (j*8)) & 0xFF); } } return bytes; }
Aunque noto que esta pregunta ha estado aquí por más de un año.
fuente
charCodeAt
devuelve una unidad de código UTF-16 de 16 bits, por lo que no necesita ninguna lógica de longitud variable. Puede simplemente llamar a charCodeAt, dividir el resultado en dos bytes de 8 bits y colocarlos en la matriz de salida (primero el byte de orden más bajo, ya que la pregunta solicita UTF-16LE).Sé que la pregunta tiene casi 4 años, pero esto es lo que funcionó sin problemas conmigo:
String.prototype.encodeHex = function () { var bytes = []; for (var i = 0; i < this.length; ++i) { bytes.push(this.charCodeAt(i)); } return bytes; }; Array.prototype.decodeHex = function () { var str = []; var hex = this.toString().split(','); for (var i = 0; i < hex.length; i++) { str.push(String.fromCharCode(hex[i])); } return str.toString().replace(/,/g, ""); }; var str = "Hello World!"; var bytes = str.encodeHex(); alert('The Hexa Code is: '+bytes+' The original string is: '+bytes.decodeHex());
o, si desea trabajar solo con cadenas y sin Array, puede usar:
String.prototype.encodeHex = function () { var bytes = []; for (var i = 0; i < this.length; ++i) { bytes.push(this.charCodeAt(i)); } return bytes.toString(); }; String.prototype.decodeHex = function () { var str = []; var hex = this.split(','); for (var i = 0; i < hex.length; i++) { str.push(String.fromCharCode(hex[i])); } return str.toString().replace(/,/g, ""); }; var str = "Hello World!"; var bytes = str.encodeHex(); alert('The Hexa Code is: '+bytes+' The original string is: '+bytes.decodeHex());
fuente
bytes
matriz no contiene 'bytes', contiene números de 16 bits, que representan la cadena en unidades de código UTF-16. Esto es casi lo que pedía la pregunta, pero en realidad solo por accidente.Aquí está la misma función que @BrunoLM publicó convertida en una función de prototipo de cadena:
String.prototype.getBytes = function () { var bytes = []; for (var i = 0; i < this.length; ++i) { bytes.push(this.charCodeAt(i)); } return bytes; };
Si define la función como tal, puede llamar al método .getBytes () en cualquier cadena:
var str = "Hello World!"; var bytes = str.getBytes();
fuente
No necesita guión bajo, solo use el mapa integrado:
var string = 'Hello World!'; document.write(string.split('').map(function(c) { return c.charCodeAt(); }));
fuente