Подтвердить что ты не робот

Как преобразовать строку UTF8 в массив байтов?

Функция .charCodeAt возвращается с кодом юникода символа. Но я бы хотел получить массив байтов. Я знаю, что если charcode превышает 127, тогда символ хранится в двух или более байтах.

var arr=[];
for(var i=0; i<str.length; i++) {
    arr.push(str.charCodeAt(i))
}
4b9b3361

Ответ 1

Логика кодирования Unicode в UTF-8 в основном:

  • Можно использовать до 4 байтов на символ. Используется наименьшее количество байтов.
  • Символы до U + 007F кодируются одним байтом.
  • Для многобайтовых последовательностей количество первых 1 бита в первом байте дает количество байтов для символа. Остальные биты первого байта могут использоваться для кодирования битов символа.
  • Байт продолжения начинается с 10, а остальные 6 бит кодируют биты символа.

Здесь функция, которую я написал некоторое время назад для кодирования строки JavaScript UTF-16 в UTF-8:

function toUTF8Array(str) {
    var utf8 = [];
    for (var i=0; i < str.length; i++) {
        var charcode = str.charCodeAt(i);
        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));
        }
        // surrogate pair
        else {
            i++;
            // 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(i) & 0x3ff));
            utf8.push(0xf0 | (charcode >>18), 
                      0x80 | ((charcode>>12) & 0x3f), 
                      0x80 | ((charcode>>6) & 0x3f), 
                      0x80 | (charcode & 0x3f));
        }
    }
    return utf8;
}

Ответ 2

JavaScript String хранится в UTF-16. Чтобы получить UTF-8, вам придется преобразовать String самостоятельно.

Один из способов - смешать encodeURIComponent(), который выведет URL-адрес в кодировке UTF-8, unescape, как упомянутый в ecmanaut.

var utf8 = unescape(encodeURIComponent(str));

var arr = [];
for (var i = 0; i < utf8.length; i++) {
    arr.push(utf8.charCodeAt(i));
}

Ответ 3

В библиотеке Google Closure есть функции для преобразования в/из UTF-8 и байтовых массивов. Если вы не хотите использовать всю библиотеку, вы можете скопировать функции отсюда. Для полноты, код для преобразования в строку в байтовый массив UTF-8:

goog.crypt.stringToUtf8ByteArray = function(str) {
  // TODO(user): Use native implementations if/when available
  var out = [], p = 0;
  for (var i = 0; i < str.length; i++) {
    var c = str.charCodeAt(i);
    if (c < 128) {
      out[p++] = c;
    } else if (c < 2048) {
      out[p++] = (c >> 6) | 192;
      out[p++] = (c & 63) | 128;
    } else if (
        ((c & 0xFC00) == 0xD800) && (i + 1) < str.length &&
        ((str.charCodeAt(i + 1) & 0xFC00) == 0xDC00)) {
      // Surrogate Pair
      c = 0x10000 + ((c & 0x03FF) << 10) + (str.charCodeAt(++i) & 0x03FF);
      out[p++] = (c >> 18) | 240;
      out[p++] = ((c >> 12) & 63) | 128;
      out[p++] = ((c >> 6) & 63) | 128;
      out[p++] = (c & 63) | 128;
    } else {
      out[p++] = (c >> 12) | 224;
      out[p++] = ((c >> 6) & 63) | 128;
      out[p++] = (c & 63) | 128;
    }
  }
  return out;
};

Ответ 4

Новый API кодирования позволяет легко кодировать и декодировать UTF-8 (используя типизированные массивы):

var encoded = new TextEncoder("utf-8").encode("Γεια σου κόσμε");
var decoded = new TextDecoder("utf-8").decode(encoded);

console.log(encoded, decoded);

Поддержка браузера не так уж и плоха, и есть полифил, который должен работать в IE11 и более старых версиях Edge.

API также поддерживает множество различных кодировок. Я использовал его для декодирования/кодирования японского текста (Shift-JIS) с помощью этого:

new TextDecoder("shift-jis").decode(new Uint8Array(textbuffer))

Ответ 5

Предполагая, что вопрос касается DOMString в качестве входных данных, и целью является получение массива, что при интерпретации строки (например, записанной в файл на диске) кодируется UTF-8:

Теперь, когда почти все современные браузеры поддерживают типизированные массивы, было бы стыдно, если этот подход не указан:

  • Согласно W3C, программное обеспечение, поддерживающее API файлов, должно принимать DOMString s в своем Blob конструктор (см. также: Строковая кодировка при построении Blob)
  • Blobs могут быть преобразованы в ArrayBuffer с помощью функции .readAsArrayBuffer() File Reader
  • Используя DataView или создав Typed Array с буфером, считываемым файловым считывателем, можно получить доступ к каждому байту массива ArrayBuffer

Пример:

// Create a Blob with an Euro-char (U+20AC)
var b = new Blob(['€']);
var fr = new FileReader();

fr.onload = function() {
    ua = new Uint8Array(fr.result);
    // This will log "3|226|130|172"
    //                  E2  82  AC
    // In UTF-16, it would be only 2 bytes long
    console.log(
        fr.result.byteLength + '|' + 
        ua[0]  + '|' + 
        ua[1] + '|' + 
        ua[2] + ''
    );
};
fr.readAsArrayBuffer(b);

Играйте с этим на JSFiddle. Я еще не оценил это, но могу представить, что это эффективно для больших DOMStrings в качестве входных данных.

Ответ 6

Вы можете сохранить строку как есть, используя FileReader.

Сохраните строку в большом двоичном объекте и вызовите readAsArrayBuffer(). Затем событие onload приводит к созданию массива, который может быть преобразован в массив Uint8Array. К сожалению, этот вызов асинхронный.

Эта маленькая функция поможет вам:

function stringToBytes(str)
{
    let reader = new FileReader();
    let done = () => {};

    reader.onload = event =>
    {
        done(new Uint8Array(event.target.result), str);
    };
    reader.readAsArrayBuffer(new Blob([str], { type: "application/octet-stream" }));

    return { done: callback => { done = callback; } };
}

Назовите это так:

stringToBytes("\u{1f4a9}").done(bytes =>
{
    console.log(bytes);
});

выход: [240, 159, 146, 169]

объяснение:

JavaScript использует UTF-16 и суррогатные пары для хранения символов юникода в памяти. Для сохранения символа юникода в необработанных двоичных байтовых потоках необходима кодировка. Обычно и в большинстве случаев для этого используется UTF-8. Если вы не используете завершение, вы не можете сохранить Unicode-символ, просто ASCII до 0x7f.

FileReader.readAsArrayBuffer() использует UTF-8.

Ответ 7

Я использовал решение Джони, и оно работало нормально, но этот намного короче.

Это было вдохновлено функцией atobUTF16() решения № 3 в обсуждении Unicode в Mozilla Base64

function convertStringToUTF8ByteArray(str) {
    let binaryArray = new Uint8Array(str.length)
    Array.prototype.forEach.call(binaryArray, function (el, idx, arr) { arr[idx] = str.charCodeAt(idx) })
    return binaryArray
}