58

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

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

9 回答 9

78

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;
}
于 2013-09-10T22:43:30.343 回答
45

JavaScriptString存储在 UTF-16中。要获得 UTF-8,您必须String自己转换。

一种方法是混合encodeURIComponent(),这将输出 UTF-8 字节的 URL 编码,unescapeecmanaut 所述

var utf8 = unescape(encodeURIComponent(str));

var arr = [];
for (var i = 0; i < utf8.length; i++) {
    arr.push(utf8.charCodeAt(i));
}
于 2013-09-10T22:06:05.350 回答
30

Encoding 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);
于 2017-09-15T13:42:42.223 回答
11

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;
};
于 2015-01-30T01:05:29.953 回答
7

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

现在几乎所有现代浏览器都支持 Typed Arrays,如果没有列出这种方法,那就太丢脸了:

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

于 2014-12-23T20:15:37.833 回答
2

您可以使用FileReader按原样保存字符串。

将字符串保存在 blob 中并调用readAsArrayBuffer()。然后 onload-event 会产生一个 arraybuffer,它可以转换为 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 和代理对将 unicode 字符存储在内存中。要在原始二进制字节流中保存 unicode 字符,需要进行编码。通常并且在大多数情况下,UTF-8 用于此目的。如果您不使用编码,则无法保存 unicode 字符,只能保存 ASCII 至 0x7f。

FileReader.readAsArrayBuffer() 使用 UTF-8。

于 2018-01-26T13:52:43.363 回答
1

我使用的是Joni 的解决方案,效果很好,但是这个要短得多。

这是受到Mozilla 的 Base64 Unicode 讨论的解决方案 #3 的 atobUTF16() 函数的启发

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
}
于 2019-05-31T22:59:45.590 回答
1

由于 JavaScript 中没有纯byte类型,我们可以将字节数组表示为数字数组,其中每个数字代表一个字节,因此将具有介于 0 和 255 之间的整数值。

这是一个简单的函数,它将 JavaScript 字符串转换为包含字符串的 UTF-8 编码的数字数组:

function toUtf8(str) {
    var value = [];
    var destIndex = 0;
    for (var index = 0; index < str.length; index++) {
        var code = str.charCodeAt(index);
        if (code <= 0x7F) {
            value[destIndex++] = code;
        } else if (code <= 0x7FF) {
            value[destIndex++] = ((code >> 6 ) & 0x1F) | 0xC0;
            value[destIndex++] = ((code >> 0 ) & 0x3F) | 0x80;
        } else if (code <= 0xFFFF) {
            value[destIndex++] = ((code >> 12) & 0x0F) | 0xE0;
            value[destIndex++] = ((code >> 6 ) & 0x3F) | 0x80;
            value[destIndex++] = ((code >> 0 ) & 0x3F) | 0x80;
        } else if (code <= 0x1FFFFF) {
            value[destIndex++] = ((code >> 18) & 0x07) | 0xF0;
            value[destIndex++] = ((code >> 12) & 0x3F) | 0x80;
            value[destIndex++] = ((code >> 6 ) & 0x3F) | 0x80;
            value[destIndex++] = ((code >> 0 ) & 0x3F) | 0x80;
        } else if (code <= 0x03FFFFFF) {
            value[destIndex++] = ((code >> 24) & 0x03) | 0xF0;
            value[destIndex++] = ((code >> 18) & 0x3F) | 0x80;
            value[destIndex++] = ((code >> 12) & 0x3F) | 0x80;
            value[destIndex++] = ((code >> 6 ) & 0x3F) | 0x80;
            value[destIndex++] = ((code >> 0 ) & 0x3F) | 0x80;
        } else if (code <= 0x7FFFFFFF) {
            value[destIndex++] = ((code >> 30) & 0x01) | 0xFC;
            value[destIndex++] = ((code >> 24) & 0x3F) | 0x80;
            value[destIndex++] = ((code >> 18) & 0x3F) | 0x80;
            value[destIndex++] = ((code >> 12) & 0x3F) | 0x80;
            value[destIndex++] = ((code >> 6 ) & 0x3F) | 0x80;
            value[destIndex++] = ((code >> 0 ) & 0x3F) | 0x80;
        } else {
            throw new Error("Unsupported Unicode character \"" 
                + str.charAt(index) + "\" with code " + code + " (binary: " 
                + toBinary(code) + ") at index " + index
                + ". Cannot represent it as UTF-8 byte sequence.");
        }
    }
    return value;
}

function toBinary(byteValue) {
    if (byteValue < 0) {
        byteValue = byteValue & 0x00FF;
    }
    var str = byteValue.toString(2);
    var len = str.length;
    var prefix = "";
    for (var i = len; i < 8; i++) {
        prefix += "0";
    }
    return prefix + str;
}
于 2020-03-27T19:40:35.207 回答
-1
function convertByte()
{
    var c=document.getElementById("str").value;
    var arr = [];
    var i=0;
    for(var ind=0;ind<c.length;ind++)
    {
        arr[ind]=c.charCodeAt(i);
        i++;
    }    
    document.getElementById("result").innerHTML="The converted value is "+arr.join("");    
}
于 2020-06-27T18:35:58.807 回答