Uint8Array在Javascript中字符串

Jac*_*ter 95 javascript

我有一些UTF-8编码数据存在于Javascript中的一系列Uint8Array元素中.有没有一种有效的方法将这些解码为常规的javascript字符串(我相信Javascript使用16位Unicode)?我不希望当时添加一个字符,因为字符串concaternation将变为CPU密集型.

Vin*_*eib 136

TextEncoderTextDecoder从所述编码标准,这是由polyfilled stringencoding库,将字符串转换和ArrayBuffers之间:

var uint8array = new TextEncoder("utf-8").encode("¢");
var string = new TextDecoder("utf-8").decode(uint8array);
Run Code Online (Sandbox Code Playgroud)

  • 对于像我这样懒惰的人,`npm install text-encoding`,`var textEncoding = require('text-encoding'); var TextDecoder = textEncoding.TextDecoder;`.不用了,谢谢. (34认同)
  • 要注意npm文本编码库,webpack bundle analyzer显示库是巨大的 (10认同)
  • @VincentScheib 浏览器删除了对除“utf-8”之外的任何其他格式的支持。所以,`TextEncoder` 参数是不必要的! (6认同)
  • 请注意,Node.js 在 v11 中添加了 `TextEncoder`/`TextDecoder` API,因此如果您只针对当前 Node 版本,则无需安装任何额外的包。 (6认同)
  • 我认为现在最好的polyfill是[FastestSmallestTextEncoderDecoder](https://github.com/anonyco/FastestSmallestTextEncoderDecoder),正如[MDN网站](https://developer.mozilla.org/en-US/docs/)推荐的那样Web/API/文本编码器)。 (3认同)

Alb*_*ert 38

这应该工作:

// 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;
}
Run Code Online (Sandbox Code Playgroud)

它与其他解决方案相比更加清晰,因为它不使用任何hacks,也不依赖于Browser JS功能,例如也适用于其他JS环境.

查看JSFiddle演示.

另请参阅相关问题:此处此处

  • 这看起来有点慢.但是我发现宇宙中唯一的片段是有效的.好找+采用! (5认同)
  • 我不明白为什么这没有更多的赞成.对于小片段来说,通过UTF-8惯例似乎非常明智.正如其他人所指出的那样,Async Blob + Filereader非常适合大文本. (5认同)
  • 效果很好,除了它不处理4+字节序列,例如`fromUTF8Array([240,159,154,133])`结果为空(而`fromUTF8Array([226,152,131])→"☃"`) (5认同)
  • 问题是如何在没有字符串连接的情况下做到这一点 (3认同)
  • 为何排除案例8、9、10和11?有什么特别的原因吗?情况15也是可能的,对吧?15(1111) 表示使用了 4 个字节,不是吗? (2认同)

arc*_*en7 35

在 NodeJS 中,我们有可用的缓冲区,并且使用它们进行字符串转换非常容易。更好的是,将 Uint8Array 转换为 Buffer 很容易。试试这个代码,它在 Node 中对我来说适用于基本上任何涉及 Uint8Arrays 的转换:

let str = Buffer.from(uint8arr.buffer).toString();
Run Code Online (Sandbox Code Playgroud)

我们只是从 Uint8Array 中提取 ArrayBuffer,然后将其转换为正确的 NodeJS 缓冲区。然后我们将 Buffer 转换为字符串(如果需要,您可以输入十六进制或 base64 编码)。

如果我们想从字符串转换回 Uint8Array,那么我们可以这样做:

let uint8arr = new Uint8Array(Buffer.from(str));
Run Code Online (Sandbox Code Playgroud)

请注意,如果您在转换为字符串时声明了类似 Base64 的编码,那么您必须使用Buffer.from(str, "base64")Base64 或您使用的任何其他编码。

如果没有模块,这将无法在浏览器中运行!NodeJS Buffers 在浏览器中不存在,因此除非您向浏览器添加 Buffer 功能,否则此方法将不起作用。这实际上很容易做到,只需使用这样的模块即可它既小又快!


dlc*_*ers 24

这是我使用的:

var str = String.fromCharCode.apply(null, uint8Arr);
Run Code Online (Sandbox Code Playgroud)

  • 这将在更大的文本上抛出`RangeError`._"超出最大调用堆栈大小"_ (27认同)
  • 从[doc](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCharCode),这似乎不能解码UTF8. (5认同)
  • 这不会从 https://en.wikipedia.org/wiki/UTF-8 上的示例 unicode 字符产生正确的结果。例如 String.fromCharCode.apply(null, new Uint8Array([0xc2, 0xa2])) 不会产生 ¢。 (2认同)

Wil*_*ott 16

在其中一个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);
}
Run Code Online (Sandbox Code Playgroud)

  • 正如你所说,除非要转换的缓冲区真的非常庞大,否则这样做会非常糟糕.同步UTF-8以一个简单的字符串(比如10-40字节)的WCHAR converstion实现的,譬如说,V8应该比一微秒少得多,而我猜想,你的代码将需要数百个倍.谢谢你们. (2认同)

kpo*_*owz 10

在节点" Buffer实例也是Uint8Array实例 "中,因此buf.toString()在这种情况下工作.

  • @doom在浏览器端,Uint8Array.toString()不会编译utf-8字符串,它会列出数组中的数值。因此,如果您拥有的是来自另一个源的 Uint8Array,而它又不是 Buffer,那么您将需要创建一个来实现这一神奇功能:`Buffer.from(uint8array).toString('utf-8')` (10认同)
  • 这在 Chrome 中不起作用。`Buffer` *仅*是nodejs。 (3认同)

Bob*_*lof 9

只要很少调用所提供的函数,并且仅用于中等大小的数组,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('');
    };
})();
Run Code Online (Sandbox Code Playgroud)

  • 这里最好的解决方案,因为它也可以处理4个字节的字符(例如emoji表情),谢谢! (2认同)
  • 其反面是什么? (2认同)

Mad*_*oop 9

Uint8Array 到 String

let str = Buffer.from(key.secretKey).toString('base64');
Run Code Online (Sandbox Code Playgroud)

字符串到 Uint8Array

let uint8arr = new Uint8Array(Buffer.from(data,'base64')); 
Run Code Online (Sandbox Code Playgroud)


sim*_*905 6

我很沮丧地看到人们没有展示如何进行双向操作,也没有展示如何在不简单的 UTF8 字符串上工作。我在 codereview.stackexchange.com 上找到了一篇文章,其中有一些运行良好的代码。我用它把古代符文转换成字节,测试字节上的一些密码,然后将东西转换回字符串。工作代码位于 github。为了清楚起见,我重命名了这些方法:

\n\n
// https://codereview.stackexchange.com/a/3589/75693\nfunction bytesToSring(bytes) {\n    var chars = [];\n    for(var i = 0, n = bytes.length; i < n;) {\n        chars.push(((bytes[i++] & 0xff) << 8) | (bytes[i++] & 0xff));\n    }\n    return String.fromCharCode.apply(null, chars);\n}\n\n// https://codereview.stackexchange.com/a/3589/75693\nfunction stringToBytes(str) {\n    var bytes = [];\n    for(var i = 0, n = str.length; i < n; i++) {\n        var char = str.charCodeAt(i);\n        bytes.push(char >>> 8, char & 0xFF);\n    }\n    return bytes;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

单元测试使用以下 UTF-8 字符串:

\n\n
    // http://kermitproject.org/utf8.html\n    // From the Anglo-Saxon Rune Poem (Rune version) \n    const secretUtf8 = `\xe1\x9a\xa0\xe1\x9b\x87\xe1\x9a\xbb\xe1\x9b\xab\xe1\x9b\x92\xe1\x9b\xa6\xe1\x9a\xa6\xe1\x9b\xab\xe1\x9a\xa0\xe1\x9a\xb1\xe1\x9a\xa9\xe1\x9a\xa0\xe1\x9a\xa2\xe1\x9a\xb1\xe1\x9b\xab\xe1\x9a\xa0\xe1\x9b\x81\xe1\x9a\xb1\xe1\x9a\xaa\xe1\x9b\xab\xe1\x9a\xb7\xe1\x9b\x96\xe1\x9a\xbb\xe1\x9a\xb9\xe1\x9b\xa6\xe1\x9b\x9a\xe1\x9a\xb3\xe1\x9a\xa2\xe1\x9b\x97\n\xe1\x9b\x8b\xe1\x9a\xb3\xe1\x9b\x96\xe1\x9a\xaa\xe1\x9b\x9a\xe1\x9b\xab\xe1\x9a\xa6\xe1\x9b\x96\xe1\x9a\xaa\xe1\x9a\xbb\xe1\x9b\xab\xe1\x9b\x97\xe1\x9a\xaa\xe1\x9a\xbe\xe1\x9a\xbe\xe1\x9a\xaa\xe1\x9b\xab\xe1\x9a\xb7\xe1\x9b\x96\xe1\x9a\xbb\xe1\x9a\xb9\xe1\x9b\xa6\xe1\x9b\x9a\xe1\x9a\xb3\xe1\x9b\xab\xe1\x9b\x97\xe1\x9b\x81\xe1\x9a\xb3\xe1\x9b\x9a\xe1\x9a\xa2\xe1\x9a\xbe\xe1\x9b\xab\xe1\x9a\xbb\xe1\x9b\xa6\xe1\x9b\x8f\xe1\x9b\xab\xe1\x9b\x9e\xe1\x9a\xab\xe1\x9b\x9a\xe1\x9a\xaa\xe1\x9a\xbe\n\xe1\x9a\xb7\xe1\x9b\x81\xe1\x9a\xa0\xe1\x9b\xab\xe1\x9a\xbb\xe1\x9b\x96\xe1\x9b\xab\xe1\x9a\xb9\xe1\x9b\x81\xe1\x9b\x9a\xe1\x9b\x96\xe1\x9b\xab\xe1\x9a\xa0\xe1\x9a\xa9\xe1\x9a\xb1\xe1\x9b\xab\xe1\x9b\x9e\xe1\x9a\xb1\xe1\x9b\x81\xe1\x9a\xbb\xe1\x9b\x8f\xe1\x9a\xbe\xe1\x9b\x96\xe1\x9b\xab\xe1\x9b\x9e\xe1\x9a\xa9\xe1\x9b\x97\xe1\x9b\x96\xe1\x9b\x8b\xe1\x9b\xab\xe1\x9a\xbb\xe1\x9b\x9a\xe1\x9b\x87\xe1\x9b\x8f\xe1\x9a\xaa\xe1\x9a\xbe\xe1\x9b\xac`;\n
Run Code Online (Sandbox Code Playgroud)\n\n

请注意,字符串长度仅为 117 个字符,但编码后的字节长度为 234。

\n\n

如果我取消注释 console.log 行,我可以看到解码的字符串与编码的字符串相同(字节通过 Shamir 的秘密共享算法传递!):

\n\n

演示编码和解码的单元测试

\n

  • 解决方案是批量处理 64k 字符。 (2认同)

小智 5

执行@Sudhir所说的,然后从逗号分隔的数字列表中获取字符串,请使用:

for (var i=0; i<unitArr.byteLength; i++) {
            myString += String.fromCharCode(unitArr[i])
        }
Run Code Online (Sandbox Code Playgroud)

如果仍然有用,它将为您提供所需的字符串

  • 这不会执行UTF8解码。 (13认同)