Как преобразовать строку UTF8 в массив байтов?
Функция .charCodeAt
возвращается с кодом юникода символа. Но я бы хотел получить массив байтов. Я знаю, что если charcode превышает 127, тогда символ хранится в двух или более байтах.
var arr=[];
for(var i=0; i<str.length; i++) {
arr.push(str.charCodeAt(i))
}
Ответы
Ответ 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
}