如何将 UTF8 字符串转换为字节数组?

IT技术 javascript utf-8
2021-02-15 12:27:02

.charCodeAt函数返回字符的 unicode 代码。但我想改为获取字节数组。我知道,如果字符码超过 127,则字符存储在两个或更多字节中。

var arr=[];
for(var i=0; i<str.length; i++) {
    arr.push(str.charCodeAt(i))
}
6个回答

UTF-8编码Unicode的逻辑基本上是:

  • 每个字符最多可以使用 4 个字节。使用尽可能少的字节数。
  • 最多 U+007F 的字符使用单个字节进行编码。
  • 对于多字节序列,第一个字节中的前导 1 位的数量给出了字符的字节数。第一个字节的其余位可用于对字符的位进行编码。
  • 连续字节以 10 开头,其他 6 位对字符的位进行编码。

这是我不久前编写的一个函数,用于在 UTF-8 中编码 JavaScript UTF-16 字符串:

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;
}
@donkaka 不过,与循环arr相比,它应该匹配forjsfiddle.net/3Uz8n
2021-04-16 12:27:02
看起来类似于onicos.com/staff/iz/amuse/javascript/expert/utf.txt,它对我在 CJK 统一扩展 B 中包含模糊的 4 字节字符的字符串有用
2021-04-17 12:27:02
比领先的答案大约 89%干得好。
2021-04-25 12:27:02
结果不一样,因为unescape(encodeURIComponent())stackoverflow.com/a/18729536/2408835
2021-04-26 12:27:02
谷歌闭包库中的一个类似函数:stringToUtf8ByteArray()字符串在 JavaScript 的内存中是 UTF16 的事实对我来说是一个开端🤔😳
2021-05-15 12:27:02

JavaScript的Strings的存储在UTF-16要获得 UTF-8,您必须String自己转换

一种方法是混合encodeURIComponent(),这将输出UTF-8字节URL编码,以unescape作为上ecmanaut提到

var utf8 = unescape(encodeURIComponent(str));

var arr = [];
for (var i = 0; i < utf8.length; i++) {
    arr.push(utf8.charCodeAt(i));
}
是的。encodeURIComponent 运行良好,但我想了解 utf8 字节码是如何生成的。
2021-04-17 12:27:02
谢谢,它有效。但我想了解它,如何编码这个unicode到utf8字节码转换。你能给我链接一篇关于它的文章吗?我没有找到
2021-04-21 12:27:02
维基百科实际上对 UTF-8 转换有很好的总结。en.wikipedia.org/wiki/UTF-8#Description这些示例演示了原始代码点的位是如何传播的,以及哪些前缀用于稍后辅助解码。编码它会因 UTF-16代理对变得复杂,但基于按位移位和使用 AND 或 OR 进行屏蔽
2021-05-07 12:27:02
这里还有一些例子,如果你想在 UTF-8 文本和十六进制、二进制或 base64 之间进行转换:jsfiddle.net/47zwb41o
2021-05-13 12:27:02
@donkaka 我在我的帖子中链接到了一个。ecmanaut.blogspot.com/2006/07/... . 您想手动逐个代码地转换它吗?
2021-05-14 12:27:02

编码API允许您既编码和解码UTF-8容易地(使用类型数组):

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

浏览器支持还不错,并且有一个polyfill应该可以在 IE11 和旧版本的 Edge 中使用。

虽然TextEncoder只能编码为UTF-8,但TextDecoder支持其他编码。我用它以这种方式解码日语文本(Shift-JIS):

// Shift-JIS encoded text; must be a byte array due to values 129 and 130.
var arr = [130, 108, 130, 102, 130, 80, 129,  64, 130, 102, 130,  96, 130, 108, 130, 100,
           129,  64, 130,  99, 130, 96, 130, 115, 130,  96, 129, 124, 130,  79, 130, 80];
// Convert to byte array
var data = new Uint8Array(arr);
// Decode with TextDecoder
var decoded = new TextDecoder("shift-jis").decode(data.buffer);
console.log(decoded);
就我而言,我实际上有一个带有 UTF-8 字符代码的 Javascript (UTF-16) 字符串。实际上比这更糟糕,因为 0x80 再次表示为其他东西(欧元符号的 unicode)等。仍在尝试制定更好的解决方案,我应该能够将数据读入数组。但不幸的是,TextDecoder 是 IE/Edge 的一个问题。
2021-04-21 12:27:02
如果您有像“DEADBEEF”这样的十六进制字节字符串,则不能直接使用它。您需要将其转换为 TypedArray 才能对其进行解码。4行代码即可完成:paste2.org/5KHPxdVO
2021-05-12 12:27:02
.decode( ) 对字符串不起作用,因此如果您尝试解码恰好是 utf8 格式的字节字符串(在某些环境中可能会发生),则没有用
2021-05-14 12:27:02

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;
};
这是更新的链接:stringToUtf8ByteArray()
2021-04-30 12:27:02
Google 将关闭移至 github。更新了链接(并且还更新了代码片段,因为函数实现也发生了变化)。
2021-05-10 12:27:02

假设问题是关于作为输入的 DOMString 并且目标是获得一个数组,当被解释为字符串(例如写入磁盘上的文件)时,将被 UTF-8 编码:

现在几乎所有的现代浏览器都支持 Typed Arrays,如果没有列出这种方法会很惭愧:

  • 根据W3C,支持 File API 的软件应该在其Blob 构造函数中接受DOMString s (另请参阅:构造 Blob 时的字符串编码
  • 可以使用文件读取器.readAsArrayBuffer()功能将Blob 转换为 ArrayBuffer
  • 使用DataView使用File Reader 读取的缓冲区构造类型化数组,可以访问 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 作为输入是有效的。

这很棒。无需在 JS 中进行疯狂的位操作,只需将其直接传递给 Blob 构造函数即可。谢谢!
2021-05-04 12:27:02