Como posso converter uma string em bytearray usando JavaScript. A saída deve ser equivalente ao código C # abaixo.
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] bytes = encoding.GetBytes(AnyString);
Como UnicodeEncoding é por padrão UTF-16 com Little-Endianness.
Edit: Eu tenho um requisito para combinar o lado do cliente gerado por bytearray com aquele gerado no lado do servidor usando o código C # acima.
javascript
shas
fonte
fonte
Respostas:
Em C # executando este
UnicodeEncoding encoding = new UnicodeEncoding(); byte[] bytes = encoding.GetBytes("Hello");
Irá criar uma matriz com
72,0,101,0,108,0,108,0,111,0
Para um caractere cujo código é maior que 255, será semelhante a este
Se você quiser um comportamento muito semelhante em JavaScript, pode fazer isso (v2 é uma solução um pouco mais robusta, enquanto a versão original só 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(', '));
fonte
Se você está procurando uma solução que funcione em node.js, você pode usar isto:
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);
fonte
Suponho que C # e Java produzam matrizes de bytes iguais. Se você tiver caracteres não ASCII, não é suficiente adicionar um 0. Meu exemplo contém alguns caracteres especiais:
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
Não sei se C # coloca BOM (Byte Order Marks), mas se estiver usando UTF-16, Java
String.getBytes
adiciona os seguintes bytes: 254 255.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:
Adicionado um caractere especial (U + 1D11E) MUSICAL SYMBOL G CLEF (fora do BPM, tomando não apenas 2 bytes em UTF-16, mas 4.
As versões atuais do JavaScript usam "UCS-2" internamente, portanto, este símbolo ocupa o espaço de 2 caracteres normais.
Não tenho certeza, mas ao usá-
charCodeAt
lo parece que obtemos exatamente os pontos de código substitutos também usados em UTF-16, portanto, caracteres não BPM são tratados corretamente.Este problema é absolutamente não trivial. Pode depender das versões e mecanismos de JavaScript usados. Portanto, se você deseja soluções confiáveis, deve dar uma olhada em:
fonte
charCodeAt
retorna uma Unidade de Código UTF-16, no intervalo 0-65535. Os caracteres fora do intervalo de 2 bytes são representados como pares substitutos, assim como em UTF-16. (A propósito, isso é verdade para strings em várias outras linguagens, incluindo Java e C #.)(charCode & 0xFF00) >> 8
é redundante, você não precisa mascará-lo antes de mudar.A maneira mais fácil em 2018 deve ser TextEncoder, mas o elemento retornado não é a matriz de bytes, é Uint8Array. (E nem todos os navegadores o suportam)
let utf8Encode = new TextEncoder(); utf8Encode.encode("eee") > Uint8Array [ 101, 101, 101 ]
fonte
new TextDecoder().decode(new TextEncoder().encode(str)) == str
.TextEncoder
: caniuseMatriz de bytes UTF-16
JavaScript codifica strings como UTF-16 , assim como C #
UnicodeEncoding
, então as matrizes de bytes devem corresponder exatamente usandocharCodeAt()
e dividindo cada par de bytes retornado em 2 bytes separados, como em: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 exemplo:
strToUtf16Bytes('🌵'); // [ 60, 216, 53, 223 ]
No entanto, se você deseja obter uma matriz de bytes UTF-8, deve transcodificar os bytes.
Matriz de bytes UTF-8
A solução parece um tanto não trivial, mas usei o código abaixo em um ambiente de produção de alto tráfego com grande sucesso ( fonte original ).
Além disso, para o leitor interessado, publiquei meus ajudantes unicode que me ajudam a trabalhar com comprimentos de string relatados por outras linguagens 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; }
fonte
Inspirado pela resposta de @hgoebl. Seu código é para UTF-16 e eu precisava de algo para US-ASCII. Portanto, aqui está uma resposta mais completa cobrindo US-ASCII, UTF-16 e 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 tem comprimento variável e não está incluído porque eu mesmo teria que escrever a codificação. UTF-8 e UTF-16 são de comprimento variável. UTF-8, UTF-16 e UTF-32 têm um número mínimo de bits como seu nome indica. Se um caractere UTF-32 tiver um ponto de código de 65, isso significa que há 3 zeros à esquerda. Mas o mesmo código para UTF-16 tem apenas 1 inicial de 0. US-ASCII, por outro lado, tem largura fixa de 8 bits, o que significa que pode ser traduzido diretamente em bytes.
String.prototype.charCodeAt
retorna um número máximo de 2 bytes e corresponde exatamente a UTF-16. Porém, para UTF-32String.prototype.codePointAt
é necessário que faz parte da proposta ECMAScript 6 (Harmony). Como charCodeAt retorna 2 bytes, que são mais caracteres possíveis do que US-ASCII pode representar, a funçãostringToAsciiByteArray
lançará nesses casos em vez de dividir o caractere ao meio e pegar um ou ambos os bytes.Observe que essa resposta não é trivial porque a codificação de caracteres não é trivial. O tipo de array de bytes que você deseja depende de qual codificação de caracteres você deseja que esses bytes representem.
javascript tem a opção de usar internamente UTF-16 ou UCS-2, mas como possui métodos que agem como se fossem UTF-16, não vejo por que qualquer navegador usaria UCS-2. Veja também: https://mathiasbynens.be/notes/javascript-encoding
Sim, eu sei que a pergunta é de 4 anos, mas eu precisava dessa resposta para mim.
fonte
'02'
se[ 48, 0, 50, 0 ]
onde, como seusstringToUtf16ByteArray
função retorna[ 0, 48, 0, 50 ]
. qual está correto?Já que não posso comentar sobre a resposta, eu usaria a resposta de Jin Izzraeel
dizendo que você poderia usar isso se quiser usar um buffer Node.js em seu navegador.
https://github.com/feross/buffer
Portanto, a objeção de Tom Stickel não é válida, e a resposta é de fato uma resposta válida.
fonte
String.prototype.encodeHex = function () { return this.split('').map(e => e.charCodeAt()) }; String.prototype.decodeHex = function () { return this.map(e => String.fromCharCode(e)).join('') };
fonte
encodeHex
retornará uma matriz de números de 16 bits, não bytes.A melhor solução que eu encontrei no local (embora provavelmente bruta) seria:
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; }
Embora eu note que essa pergunta está aqui há mais de um ano.
fonte
charCodeAt
retorna uma unidade de código UTF-16 de 16 bits, portanto, você não precisa de nenhuma lógica de comprimento variável. Você pode simplesmente chamar charCodeAt, dividir o resultado em dois bytes de 8 bits e colocá-los na matriz de saída (byte de ordem mais baixa primeiro, pois a questão pede UTF-16LE).Eu sei que a pergunta tem quase 4 anos, mas isto é o que funcionou bem comigo:
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());
ou, se quiser trabalhar apenas com strings e sem Array, você pode 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());
fonte
bytes
matriz não contém 'bytes', ela contém números de 16 bits, que representam a string em unidades de código UTF-16. Isso é quase o que a pergunta pedia, mas na verdade apenas por acidente.Aqui está a mesma função que @BrunoLM postou convertida em uma função de protótipo String:
String.prototype.getBytes = function () { var bytes = []; for (var i = 0; i < this.length; ++i) { bytes.push(this.charCodeAt(i)); } return bytes; };
Se você definir a função como tal, poderá chamar o método .getBytes () em qualquer string:
var str = "Hello World!"; var bytes = str.getBytes();
fonte
Você não precisa de sublinhado, apenas use o mapa integrado:
var string = 'Hello World!'; document.write(string.split('').map(function(c) { return c.charCodeAt(); }));
fonte