Как преобразовать строку в массив байтов с помощью JavaScript. Вывод должен быть эквивалентом приведенного ниже кода C #.
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] bytes = encoding.GetBytes(AnyString);
Поскольку UnicodeEncoding по умолчанию - UTF-16 с Little-Endianness.
Изменить: у меня есть требование сопоставить клиентскую сторону, сгенерированную байтовым массивом, с той, которая была создана на стороне сервера, с использованием приведенного выше кода C #.
javascript
шас
источник
источник
Ответы:
В C # работает это
UnicodeEncoding encoding = new UnicodeEncoding(); byte[] bytes = encoding.GetBytes("Hello");
Создадим массив с
72,0,101,0,108,0,108,0,111,0
Для символа, код которого больше 255, это будет выглядеть так
Если вам нужно очень похожее поведение в JavaScript, вы можете сделать это (v2 - немного более надежное решение, в то время как исходная версия будет работать только для 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(', '));
источник
Если вы ищете решение, которое работает в node.js, вы можете использовать это:
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);
источник
Я полагаю, что C # и Java создают равные массивы байтов. Если у вас есть символы, отличные от ASCII, недостаточно добавить дополнительный 0. Мой пример содержит несколько специальных символов:
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
Я не знаю, размещает ли C # BOM (метки порядка байтов), но при использовании UTF-16 Java
String.getBytes
добавляет следующие байты: 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
Редактировать:
Добавлен специальный символ (U + 1D11E) MUSICAL SYMBOL G CLEF (за пределами BPM, поэтому в UTF-16 используются не только 2 байта, но и 4 байта.
В текущих версиях JavaScript внутренне используется "UCS-2", поэтому этот символ занимает пространство из двух обычных символов.
Я не уверен, но при использовании
charCodeAt
кажется, что мы получаем именно те суррогатные кодовые точки, которые также используются в UTF-16, поэтому символы, не относящиеся к BPM, обрабатываются правильно.Эта проблема совершенно нетривиальная. Это может зависеть от используемых версий и движков JavaScript. Поэтому, если вам нужны надежные решения, вам следует взглянуть на:
источник
charCodeAt
возвращает кодовую единицу UTF-16 в диапазоне 0-65535. Символы вне 2-байтового диапазона представлены как суррогатные пары, как в UTF-16. (Кстати, это верно для строк на нескольких других языках, включая Java и C #.)(charCode & 0xFF00) >> 8
избыточно, маскировать перед переключением не нужно.Самым простым способом в 2018 году должен быть TextEncoder, но возвращаемый элемент не является байтовым массивом, это Uint8Array. (И не все браузеры это поддерживают)
let utf8Encode = new TextEncoder(); utf8Encode.encode("eee") > Uint8Array [ 101, 101, 101 ]
источник
new TextDecoder().decode(new TextEncoder().encode(str)) == str
.TextEncoder
: caniuseБайтовый массив UTF-16
JavaScript кодирует строки как UTF-16 , как и C #
UnicodeEncoding
, поэтому байтовые массивы должны точно совпадать с использованиемcharCodeAt()
и разделением каждой возвращаемой пары байтов на 2 отдельных байта, как в: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; }
Например:
strToUtf16Bytes('🌵'); // [ 60, 216, 53, 223 ]
Однако, если вы хотите получить массив байтов UTF-8, вы должны перекодировать байты.
Байтовый массив UTF-8
Решение кажется несколько нетривиальным, но я с большим успехом использовал приведенный ниже код в производственной среде с высоким трафиком ( исходный код ).
Кроме того, для заинтересованного читателя я опубликовал свои помощники юникода, которые помогают мне работать с длинами строк, сообщаемыми другими языками, такими как 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; }
источник
Вдохновленный ответом @hgoebl. Его код предназначен для UTF-16, а мне нужно что-то для US-ASCII. Итак, вот более полный ответ, охватывающий US-ASCII, UTF-16 и 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 имеет переменную длину и не включен, потому что мне пришлось бы писать кодировку самостоятельно. UTF-8 и UTF-16 имеют переменную длину. UTF-8, UTF-16 и UTF-32 имеют минимальное количество бит, как указывает их название. Если символ UTF-32 имеет кодовую точку 65, это означает, что есть 3 ведущих нуля. Но тот же код для UTF-16 имеет только 1 ведущий 0. US-ASCII, с другой стороны, имеет фиксированную ширину 8 бит, что означает, что он может быть напрямую преобразован в байты.
String.prototype.charCodeAt
возвращает максимальное количество 2 байта и точно соответствует UTF-16. ОднакоString.prototype.codePointAt
требуется UTF-32, который является частью предложения ECMAScript 6 (Harmony). Поскольку charCodeAt возвращает 2 байта, что является большим количеством возможных символов, чем может представить US-ASCII, функцияstringToAsciiByteArray
в таких случаях выбрасывает вместо разделения символа пополам и получения одного или обоих байтов.Обратите внимание, что этот ответ нетривиален, потому что кодировка символов нетривиальна. Какой тип массива байтов вам нужен, зависит от того, какую кодировку символов вы хотите представлять в этих байтах.
javascript имеет возможность внутреннего использования либо UTF-16, либо UCS-2, но поскольку у него есть методы, которые действуют так, как будто это UTF-16, я не понимаю, почему какой-либо браузер будет использовать UCS-2. См. Также: https://mathiasbynens.be/notes/javascript-encoding
Да, я знаю, что этому вопросу 4 года, но мне нужен был этот ответ для себя.
источник
'02'
являются ,[ 48, 0, 50, 0 ]
где , как вашиstringToUtf16ByteArray
возвратов функции[ 0, 48, 0, 50 ]
. какой из них правильный?Поскольку я не могу комментировать ответ, я бы опирался на ответ Джина Иззраила
сказав, что вы можете использовать это, если хотите использовать буфер Node.js в своем браузере.
https://github.com/feross/buffer
Следовательно, возражение Тома Стикеля недействительно, и ответ действительно является действительным.
источник
String.prototype.encodeHex = function () { return this.split('').map(e => e.charCodeAt()) }; String.prototype.decodeHex = function () { return this.map(e => String.fromCharCode(e)).join('') };
источник
encodeHex
вернет массив 16-битных чисел, а не байтов.Лучшее решение, которое я придумал на месте (хотя, скорее всего, грубое), было бы:
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; }
Хотя я заметил, что этот вопрос был здесь больше года.
источник
charCodeAt
возвращает 16-битный кодовый блок UTF-16, поэтому вам не нужна логика переменной длины. Вы можете просто вызвать charCodeAt, разделить результат на два 8-битных байта и поместить их в выходной массив (сначала байт младшего порядка, так как вопрос запрашивает UTF-16LE).Я знаю, что этому вопросу уже почти 4 года, но вот что у меня сработало:
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());
или, если вы хотите работать только со строками и без массива, вы можете использовать:
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());
источник
bytes
Массив не содержит «байты», он содержит 16-разрядные числа, которые представляют собой строку в UTF-16 единиц коды. Это почти то, о чем спрашивали, но на самом деле только случайно.Вот та же функция, которую опубликовал @BrunoLM, преобразованная в функцию-прототип String:
String.prototype.getBytes = function () { var bytes = []; for (var i = 0; i < this.length; ++i) { bytes.push(this.charCodeAt(i)); } return bytes; };
Если вы определяете функцию как таковую, вы можете вызвать метод .getBytes () для любой строки:
var str = "Hello World!"; var bytes = str.getBytes();
источник
Вам не нужно подчеркивание, просто используйте встроенную карту:
var string = 'Hello World!'; document.write(string.split('').map(function(c) { return c.charCodeAt(); }));
источник