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

时间:2013-09-10 21:56:01

标签: javascript utf-8

.charCodeAt函数返回caracter的unicode代码。但我想得到字节数组。我知道,如果charcode超过127,那么该字符将存储在两个或更多字节中。

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

9 个答案:

答案 0 :(得分:55)

在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;
}

答案 1 :(得分:32)

JavaScript Stringstored in UTF-16。要获得UTF-8,您必须自己转换String

一种方法是将encodeURIComponent()unescape混合,将mentioned on ecmanaut与{{3}}混合输出UTF-8字节。

var utf8 = unescape(encodeURIComponent(str));

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

答案 2 :(得分:8)

Google Closure库具有转换为UTF-8和字节数组的功能。如果您不想使用整个库,可以从here复制函数。为完整起见,将字符串转换为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;
};

答案 3 :(得分:6)

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

现在几乎所有的现代浏览器support Typed Arrays,如果没有列出这种方法,就会感到羞耻:

  • 根据W3C,支持File API的软件应该在 Blob构造函数中接受 DOMString (另请参阅:String encoding when constructing a Blob)< / LI>
  • 可以使用文件阅读器的<{1}}功能将Blob转换为ArrayBuffer
  • 使用 DataView 或使用文件读取器读取的缓冲区构建类型化数组,可以访问ArrayBuffer的每个字节

示例:

.readAsArrayBuffer()

JSFiddle上播放。我还没有对此进行基准测试,但我可以想象这对于大型DOMStrings来说是有效的输入。

答案 4 :(得分:6)

新的Encoding API似乎让您轻松编码和解码UTF-8(使用类型化数组):

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

console.log(encoded, decoded);

浏览器支持isn't too bad,但Microsoft Edge目前不支持。有一个polyfill应该可以在IE11和Edge中使用。

API也支持许多不同的编码。我使用它来解码/编码PS2存储卡中的日文文本(Shift-JIS):

new TextDecoder("shift-jis").decode(new Uint8Array(textbuffer))

答案 5 :(得分: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。如果不使用enconding,则无法保存unicode字符,只能将ASCII保存为0x7f。

FileReader.readAsArrayBuffer()使用UTF-8。

答案 6 :(得分: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;
}

答案 7 :(得分:0)

我使用的是Joni's solution,它工作正常,但是这个代码要短得多。

这是受Mozilla's Base64 Unicode discussion的解决方案#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
}

答案 8 :(得分:0)

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("");    
}