我有一些在JavaScript中作为Uint8Array元素范围存在的UTF-8编码数据。是否有一种高效的方法将其解码为常规JavaScript字符串(我相信JavaScript使用16位Unicode)?我不想逐个字符添加,因为字符串连接将变得CPU密集。
我有一些在JavaScript中作为Uint8Array元素范围存在的UTF-8编码数据。是否有一种高效的方法将其解码为常规JavaScript字符串(我相信JavaScript使用16位Unicode)?我不想逐个字符添加,因为字符串连接将变得CPU密集。
TextEncoder
和 TextDecoder
是来自编码标准的函数。它们可通过stringencoding 库进行 polyfill,用于字符串和 ArrayBuffers 之间的转换:
var uint8array = new TextEncoder().encode("someString");
var string = new TextDecoder().decode(uint8array);
npm install text-encoding
,然后输入以下代码:var textEncoding = require('text-encoding'); var TextDecoder = textEncoding.TextDecoder;
。但我不感兴趣。 - Evan HuTextEncoder
/TextDecoder
API,因此如果你只针对当前的 Node 版本,就不需要安装任何额外的包。 - Loilo这应该可以正常工作:
// http://www.onicos.com/staff/iz/amuse/javascript/expert/utf.txt
/* utf.js - UTF-8 <=> UTF-16 convertion
*
* Copyright (C) 1999 Masanao Izumo <iz@onicos.co.jp>
* Version: 1.0
* LastModified: Dec 25 1999
* This library is free. You can redistribute it and/or modify it.
*/
function Utf8ArrayToStr(array) {
var out, i, len, c;
var char2, char3;
out = "";
len = array.length;
i = 0;
while(i < len) {
c = array[i++];
switch(c >> 4)
{
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
// 0xxxxxxx
out += String.fromCharCode(c);
break;
case 12: case 13:
// 110x xxxx 10xx xxxx
char2 = array[i++];
out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
break;
case 14:
// 1110 xxxx 10xx xxxx 10xx xxxx
char2 = array[i++];
char3 = array[i++];
out += String.fromCharCode(((c & 0x0F) << 12) |
((char2 & 0x3F) << 6) |
((char3 & 0x3F) << 0));
break;
}
}
return out;
}
相比其他解决方案,它更加干净,因为它不使用任何黑科技,也不依赖于浏览器JS函数,例如在其他JS环境中也可以工作。
查看JSFiddle演示。
fromUTF8Array([240,159,154,133])
结果为空(而fromUTF8Array([226,152,131])→"☃"
)。 - unhammer这是我使用的:
var str = String.fromCharCode.apply(null, uint8Arr);
在NodeJS中,我们可以使用缓冲区(Buffers),并且使用它们进行字符串转换非常容易。更好的是,将Uint8Array转换为Buffer也很容易。尝试这段代码,在涉及Uint8Arrays的任何转换中,对我来说在Node中都有效:
let str = Buffer.from(uint8arr.buffer).toString();
我们只是从Uint8Array中提取ArrayBuffer,然后将其转换为适当的NodeJS缓冲区。然后我们将缓冲区转换为字符串(如果需要可以加入十六进制或base64编码)。
如果我们想要从字符串转换回Uint8Array,那么我们会这样做:
let uint8arr = new Uint8Array(Buffer.from(str));
请注意,如果在转换为字符串时声明了像base64这样的编码方式,则必须使用Buffer.from(str, "base64")
来使用base64或者使用其他编码方式。
在浏览器中没有模块的情况下,这将无法工作! 浏览器中不存在NodeJS缓冲区,因此除非您在浏览器中添加缓冲区功能,否则此方法将无法工作。不过,这实际上很容易做到,只需使用像这个这样的模块,它既小又快速!
在 Node 中,"Buffer
实例也是 Uint8Array
实例",因此在这种情况下buf.toString()
也能正常工作。
Buffer
也是Uint8Array
。谢谢! - LeOn - Han LiBuffer.from(uint8array).toString('utf-8')
。请注意保持原文意思,并使翻译通俗易懂。 - Joachim LousBuffer
仅适用于nodejs。 - John HenckelUint8Array
。所有的缓冲区都是Uint8Arrays,但并非所有的Uint8Arrays都是缓冲区。Joachim的答案是正确的,但不幸的是,根据Node的文档,Buffer.from
在这种情况下会创建一个副本,而不是视图。 - Coderer这段代码是从Chrome的示例应用程序中找到的,它适用于较大的数据块,并且可以接受异步转换。
/**
* Converts an array buffer to a string
*
* @private
* @param {ArrayBuffer} buf The buffer to convert
* @param {Function} callback The function to call when conversion is complete
*/
function _arrayBufferToString(buf, callback) {
var bb = new Blob([new Uint8Array(buf)]);
var f = new FileReader();
f.onload = function(e) {
callback(e.target.result);
};
f.readAsText(bb);
}
虽然Albert提供的解决方案对于不频繁调用且仅用于中等大小数组的函数效果良好,但对于大型数组则极其低效。以下是一种增强版的vanilla JavaScript解决方案,适用于Node和浏览器,并具有以下优点:
• 对所有八位字节数组大小都能高效工作
• 不产生任何中间丢弃字符串
• 在现代JS引擎上支持4字节字符(否则将替换为“?”)
var utf8ArrayToStr = (function () {
var charCache = new Array(128); // Preallocate the cache for the common single byte chars
var charFromCodePt = String.fromCodePoint || String.fromCharCode;
var result = [];
return function (array) {
var codePt, byte1;
var buffLen = array.length;
result.length = 0;
for (var i = 0; i < buffLen;) {
byte1 = array[i++];
if (byte1 <= 0x7F) {
codePt = byte1;
} else if (byte1 <= 0xDF) {
codePt = ((byte1 & 0x1F) << 6) | (array[i++] & 0x3F);
} else if (byte1 <= 0xEF) {
codePt = ((byte1 & 0x0F) << 12) | ((array[i++] & 0x3F) << 6) | (array[i++] & 0x3F);
} else if (String.fromCodePoint) {
codePt = ((byte1 & 0x07) << 18) | ((array[i++] & 0x3F) << 12) | ((array[i++] & 0x3F) << 6) | (array[i++] & 0x3F);
} else {
codePt = 63; // Cannot convert four byte code points, so use "?" instead
i += 3;
}
result.push(charCache[codePt] || (charCache[codePt] = charFromCodePt(codePt)));
}
return result.join('');
};
})();
Uint8Array 转为字符串
let str = Buffer.from(key.secretKey).toString('base64');
将字符串转换为Uint8Array
let uint8arr = new Uint8Array(Buffer.from(data,'base64'));
按照@Sudhir所说的做,然后从逗号分隔的数字列表中获取一个字符串,使用以下代码:
for (var i=0; i<unitArr.byteLength; i++) {
myString += String.fromCharCode(unitArr[i])
}
String.fromCharCode.apply(null, unitArr);
。正如提到的那样,它不能处理UTF8编码,但是如果您只需要ASCII支持而没有访问TextEncoder / TextDecoder,则有时这足够简单。 - Ten Bitcomb我很沮丧地发现,人们没有展示如何双向操作,或者展示在非平凡的UTF8字符串上工作的情况。我在codereview.stackexchange.com上找到了一些代码,它可以很好地工作。我用它将古代符文转换为字节,对字节进行测试,然后将其转换回字符串。可工作的代码在这里的Github上。我为了清晰起见重命名了方法:
// https://codereview.stackexchange.com/a/3589/75693
function bytesToSring(bytes) {
var chars = [];
for(var i = 0, n = bytes.length; i < n;) {
chars.push(((bytes[i++] & 0xff) << 8) | (bytes[i++] & 0xff));
}
return String.fromCharCode.apply(null, chars);
}
// https://codereview.stackexchange.com/a/3589/75693
function stringToBytes(str) {
var bytes = [];
for(var i = 0, n = str.length; i < n; i++) {
var char = str.charCodeAt(i);
bytes.push(char >>> 8, char & 0xFF);
}
return bytes;
}
单元测试使用此UTF-8字符串:
// http://kermitproject.org/utf8.html
// From the Anglo-Saxon Rune Poem (Rune version)
const secretUtf8 = `ᚠᛇᚻ᛫ᛒᛦᚦ᛫ᚠᚱᚩᚠᚢᚱ᛫ᚠᛁᚱᚪ᛫ᚷᛖᚻᚹᛦᛚᚳᚢᛗ
ᛋᚳᛖᚪᛚ᛫ᚦᛖᚪᚻ᛫ᛗᚪᚾᚾᚪ᛫ᚷᛖᚻᚹᛦᛚᚳ᛫ᛗᛁᚳᛚᚢᚾ᛫ᚻᛦᛏ᛫ᛞᚫᛚᚪᚾ
ᚷᛁᚠ᛫ᚻᛖ᛫ᚹᛁᛚᛖ᛫ᚠᚩᚱ᛫ᛞᚱᛁᚻᛏᚾᛖ᛫ᛞᚩᛗᛖᛋ᛫ᚻᛚᛇᛏᚪᚾ᛬`;
chars
太大,String.fromCharCode.apply(null, chars)
会出错。 - Marc J. Schmidt
u8array.toString()
。当您调用fs.readFile
时,它会暴露Uint8Array对象。 - jcubicUint8Array
对象,调用toString
方法会返回逗号分隔的数字字符串,例如在Chrome 79中返回"91,50,48,49,57,45,"
。 - kolenbuffer.toString("utf8", start, end)
将 Node.js 中的Buffer
转换为 JavaScript 字符串,其中end = start + length
。不幸的是,浏览器没有Buffer
,它们只有Uint8Array
。因此,对于浏览器,您可以使用new TextDecoder().decode(uint8array.subarray(start, end))
。这也适用于 Node.js,因为Buffer
是Uint8Array
的子类。 - Aadit M Shah