如何解释 UTF-8 编码的平假名的字节?

How to interpret bytes for UTF-8 encoded Hiragana?

我有一个字符串“はい”,我想了解它是如何表示为字节的。

Number.prototype.toBits = function () {
    let str = this.toString(2);
    return str.padStart(8, "0");
}
let ja = "はい";
console.log(ja);
let buf = Buffer.from(ja);
for (const c of buf) {
    console.log(c + "=" + c.toBits());
}

产生:

はい
227=11100011
129=10000001
175=10101111
227=11100011
129=10000001
132=10000100

在Unicode table中,字符“は”是306F,字符“い”是3044。

我知道前导“1”位表示这是 Unicode,下一个 0 之前的 1 的数量是 Unicode 中的字节数。不明白306F怎么变成11100011 10000001 10101111

根据UTF-8,U+0800 和 U+FFFF 之间的代码点(U+306F 满足)将被编码为 3 个字节,将它们的位分布在模式中

  1110.... 10...... 10......

0x306F 的二进制表示为 0b11000001101111,符合空缺:

| ....0011 ..000001 ..101111

它们共同构成了您正在观察的内容:

= 11100011 10000001 10101111

最高有效位 (MSB) 是 1 这一事实表明它是一个 UTF-8 多字节序列。如果前两位是 11 那么它就是序列的 start;如果 10 它是序列的 延续 。实际代码点的位存储在起始字节和连续字节的 "unused" 部分;存储值所需的字节数(以及起始字节所指示的字节数)。

注意如何在字节序列中 "drop in anywhere" 并将自己与字符的开头对齐:如果 MSB=0 那么它是一个单字节字符(ASCII 兼容)。如果 MSBs=10 它是一个连续字节,您应该向后走以找到起始字节。起始字节后应始终跟在它承诺的连续字节数之后。 UTF 编码完全使用表示任何给定 Unicode 代码点所需的字节数。