如何将 UTF8 ArrayBuffer 转换为 UTF16 JavaScript 字符串

Lan*_*ard 7 javascript encoding utf-8 arraybuffer

这里的答案让我开始了解如何使用 ArrayBuffer:

在字符串和 ArrayBuffers 之间转换

但是,他们有很多不同的方法。主要是这样的:

function ab2str(buf) {
  return String.fromCharCode.apply(null, new Uint16Array(buf));
}

function str2ab(str) {
  var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char
  var bufView = new Uint16Array(buf);
  for (var i=0, strLen=str.length; i<strLen; i++) {
    bufView[i] = str.charCodeAt(i);
  }
  return buf;
}
Run Code Online (Sandbox Code Playgroud)

我想澄清一下 UTF8 和 UTF16 编码之间的区别,因为我不是 100% 确定这是正确的。

所以在 JavaScript 中,据我所知,所有字符串都是 UTF16 编码的。但是您在自己的 ArrayBuffer 中可能拥有的原始字节可以采用任何编码。

所以说我已经从 XMLHttpRequest 向浏览器提供了一个 ArrayBuffer,来自后端的那些字节是 UTF8 编码的:

var r = new XMLHttpRequest()
r.open('GET', '/x', true)
r.responseType = 'arraybuffer'
r.onload = function(){
  var b = r.response
  if (!b) return
  var v = new Uint8Array(b)
}
r.send(null)
Run Code Online (Sandbox Code Playgroud)

所以现在我们b从rUint8Array 视图中的响应中获得了 ArrayBuffer v。

问题是,如果我想将其转换为 JavaScript 字符串,该怎么做。

根据我的理解,我们所拥有的原始字节v以 UTF8 编码(并被发送到以 UTF8 编码的浏览器)。如果我们要这样做,我认为它不会正常工作:

function ab2str(buf) {
  return String.fromCharCode.apply(null, new Uint16Array(buf));
}
Run Code Online (Sandbox Code Playgroud)

根据我对我们使用 UTF8 而 JavaScript 字符串使用 UTF16 这一事实的理解,您需要这样做:

function ab2str(buf) {
  return String.fromCharCode.apply(null, new Uint8Array(buf));
}
Run Code Online (Sandbox Code Playgroud)

所以使用 Uint8Array 而不是 Uint16Array。这是第一个问题,如何从utf8 bytes -> js string.

第二个问题是现在如何从 JavaScript 字符串返回到 UTF8 字节。也就是说,我不确定这会正确编码:

function str2ab(str) {
  var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char
  var bufView = new Uint16Array(buf);
  for (var i=0, strLen=str.length; i<strLen; i++) {
    bufView[i] = str.charCodeAt(i);
  }
  return buf;
}
Run Code Online (Sandbox Code Playgroud)

不过,我不确定要在此更改什么,以返回 UTF8 ArrayBuffer。这样的事情似乎不正确:

function str2ab(str) {
  var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char
  var bufView = new Uint8Array(buf);
  for (var i=0, strLen=str.length; i<strLen; i++) {
    bufView[i] = str.charCodeAt(i);
  }
  return buf;
}
Run Code Online (Sandbox Code Playgroud)

无论如何,我只是想弄清楚如何从后端编码字符串的 UTF8 字节到前端的 UTF16 JavaScript 字符串。

za-*_*-ek 2

我们需要一些假设来理解发生了什么:

\n

1.JS使用UTF-16

\n

首先,js 使用 UTF-16 来存储符号,正如在 unicode 字符串部分中提到的:\n https://developer.mozilla.org/en-US/docs/Web/API/btoa

\n

2.UTF-16和UTF-8

\n

UTF-8和UTF-16并不意味着一个符号由一个字节或两个字节表示。UTF-8如utf-16是一种变长编码。

\n

3.ArrayBuffer和编码

\n
"hello" by one byte (Uint8Array): [104, 101, 108, 108, 111]\nthe same by two bytes (Uint16Array): [0, 104, 0, 101, 0, 108, 0, 108, 0, 111]\n
Run Code Online (Sandbox Code Playgroud)\n

ArrayBuffer 中没有编码,因为 ArrayBuffer 代表数字。

\n

对第二个数组的迭代将与对第一个数组的迭代不同。您知道两字节数字不能打包到一字节数字中。

\n
\n

当您收到来自服务器的 utf-8 响应时 - 您收到的是字节序列,如果您收到的数据按每个符号一个字节存储,您的代码将正常工作 - 它适用于 [a-zA-Z0-9 等符号] 和常见的标点符号。但是,如果您收到一个以 UTF-8 格式存储两个字节的符号,则转录到 UTF-16 上将不正确:

\n
0xC3 0xA5 (one symbol \xc3\xa5) -> 0x00 0xC3 0x00 0xA5 (two symbols "\xc3\x83\xc2\xa5")\n
Run Code Online (Sandbox Code Playgroud)\n
\n

因此,如果您不会传输拉丁符号、数字和标点符号范围之外的符号,您可以使用您的代码,即使它不正确,它也会正常工作。

\n