Как преобразовать строку в Bytearray

Как преобразовать строку в bytearray с помощью JavaScript. Вывод должен быть эквивалентным приведенному ниже С# -коду.

UnicodeEncoding encoding = new UnicodeEncoding();
byte[] bytes = encoding.GetBytes(AnyString);

Как UnicodeEncoding по умолчанию UTF- 16 с Little- Endianness.

Изменить: У меня есть требование сопоставления связанной с bytearray клиентской стороны с той, что сгенерирована на стороне сервера, используя вышеуказанный код С#.

Ответ 1

В С# выполняется это

UnicodeEncoding encoding = new UnicodeEncoding();
byte[] bytes = encoding.GetBytes("Hello");

Создает массив с

72,0,101,0,108,0,108,0,111,0

byte array

Для символа, который превышает 255, он будет выглядеть следующим образом:

byte array

Если вы хотите очень похожего поведения в 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(', '));

Ответ 2

Если вы ищете решение, которое работает в 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);

Ответ 3

Я полагаю, что С# и Java производят равные байтовые массивы. Если у вас есть символы non- 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

Я не знаю, добавляет ли С# 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

Edit:

Добавлен специальный символ (U+ 1D11E) МУЗЫКАЛЬНЫЙ СИМВОЛ G CLEF (вне BPM, поэтому берутся не только 2 байта в UTF- 16, но 4.

В современных версиях JavaScript используется "UCS- 2" внутри, поэтому этот символ занимает пробел в 2 нормальных символа.

Я не уверен, но при использовании charCodeAt кажется, что мы получаем точно суррогатные кодовые точки, также используемые в UTF- 16, поэтому non- символы BPM обрабатываются правильно.

Эта проблема абсолютно non- тривиальна. Это может зависеть от используемых версий JavaScript и движков. Поэтому, если вам нужны надежные решения, вы должны взглянуть на:

Ответ 4

Вдохновленный @hgoebl ответом. Его код для UTF- 16, и мне нужно что-то для US- ASCII. Итак, вот более полный ответ, охватывающий US- ASCII, UTF- 16 и UTF- 32.

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;
}
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;
}
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 ведущие 0. Но тот же код для UTF- 16 имеет только 1 ведущий 0. US- ASCII, с другой стороны, это бит фиксированной ширины 8-, что означает, что он может быть непосредственно переведен в байты.

String.prototype.charCodeAt возвращает максимальное количество 2 байтов и точно соответствует UTF- 16. Однако для UTF- 32 String.prototype.codePointAt требуется, что является частью предложения ECMAScript 6 (Harmony). Поскольку charCodeAt возвращает 2 байта, которые являются более возможными символами, чем US- ASCII может представлять, функция stringToAsciiByteArray будет вызывать в таких случаях вместо разделения символа пополам и принятия одного или обоих байтов.

Обратите внимание, что этот ответ non- тривиальный, поскольку кодировка символов non- тривиальна. Какой размер байтового массива вы хотите, зависит от того, какую кодировку символов вы хотите представить этим байтам.

javascript имеет возможность внутреннего использования UTF- 16 или UCS- 2, но поскольку у него есть методы, которые действуют как UTF- 16, я не понимаю, почему какой-либо браузер использовал бы UCS- 2. Также см.: https://mathiasbynens.be/notes/javascript-encoding

Да, я знаю, что вопрос 4 года, но мне нужен этот ответ для себя.

Ответ 5

Принятый ответ кажется неверным.

JavaScript кодирует строки как UTF-16, поэтому вы должны перекодировать многобайтовые символы 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;
}

Ответ 6

Самым простым способом в 2018 году должен быть TextEncoder, но возвращаемый элемент не является байтовым массивом, это Uint8Array. (И не все браузеры его поддерживают)

let utf8Encode = new TextEncoder();
utf8Encode.encode("eee")
> Uint8Array [ 101, 101, 101 ]

Ответ 7

Я знаю, что вопрос почти 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());

Ответ 8

Поскольку я не могу прокомментировать ответ, я опишу ответ Джин Иззраил

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);

сказав, что вы можете использовать это, если хотите использовать буфер Node.js в своем браузере.

https://github.com/feross/buffer

Следовательно, возражение Тома Стиллеля неверно, и ответ действительно является действительным ответом.

Ответ 9

String.prototype.encodeHex = function () {
    return this.split('').map(e => e.charCodeAt())
};

String.prototype.decodeHex = function () {    
    return this.map(e => String.fromCharCode(e)).join('')
};

Ответ 10

Вот те же функции, которые @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();

Ответ 11

Лучшее решение, которое я придумал на месте (хотя, скорее всего, грубо), будет:

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;
}

Хотя я замечаю, что этот вопрос существует уже более года.

Ответ 12

Вам не нужно подчеркивать, просто используйте built- на карте:

var string = 'Hello World!';

document.write(string.split('').map(function(c) { return c.charCodeAt(); }));