簡體   English   中英

一個 3 字節寬的 UTF-8 字符如何只使用一個 UTF-16 代碼單元?

[英]How can a 3-byte wide UTF-8 character only use a single UTF-16 code unit?

從這個參考:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length#Description

它指出 string.length 的值實際上是 UTF-16 代碼單元的數量,而不是字符數。

我顯然天真地假設任何 3 或 4 個字節寬的 UTF-8 字符都必須占用 2 個 UTF-16 代碼單元。 這就是我的意思:

我對字符串做了一些實驗: 😀œ´®†¥¨ˆøπ¬˚∆˙©ƒ∂ßåΩ≈ç√∫˜µ≤ユーザーコードa ,其中包含 1、2、3 和 4 字節寬的字符. 我得到了一些令人驚訝的結果。

每個 UTF-16 代碼單元的寬度為 2 個字節。 字符串中的字符數為 35。取字符串的 string.length 等於 36,這意味着只有一個字符占用了 2 個 UTF-16 代碼單元,但有幾個 UTF-8 字符的寬度為 3 和 4 個字節。

使用下面的代碼,我檢查了每個 UTF-8 字符、它使用的字節數以及它​​的 string.length。 有趣的是,所有 3 字節的 UTF-8 字符都只使用一個 UTF-16 代碼單元。 唯一需要 2 個代碼單元的字符是 4 字節寬的表情符號。

有人可以解釋一下這是怎么回事嗎? 謝謝!

代碼:

function iterateCharacters(str) {
  let te = new TextEncoder();
  let totalBytes = 0;
  let totalCodeUnits1 = 0;
  let totalCodeUnits2 = 0;

  let arr = [...str];
  for (let i = 0; i < arr.length; i++) {
    let bytes = te.encode(arr[i]).length;
    let length = arr[i].length;
    totalBytes += bytes;
    console.log("    i: " + i + "    char: " + arr[i] + "    bytes: " + bytes + "    length: " + length);
    // Erroneous assumption that more than 2 utf8 bytes would occupy 2 UTF-16 code units:
    totalCodeUnits1 += bytes < 3 ? 1 : 2;
    totalCodeUnits2 += length;
  }
  console.log("    total UTF-16 code units (erroneous calculation):  " + totalCodeUnits1)
  console.log("    total UTF-16 code units (correct calculation):    " + totalCodeUnits2)
  console.log("    total characters:                                 " + arr.length)
  console.log("    total UTF-8 bytes:                                " + totalBytes)
}

var sample = "😀œ´®†¥¨ˆøπ¬˚∆˙©ƒ∂ßåΩ≈ç√∫˜µ≤ユーザーコードa";

iterateCharacters(sample);
console.log("total number of UTF-16 code units:  " + sample.length);
console.log("total number of characters:         " + [...sample].length);
console.log("total number of UTF-8 bytes:        " + (new TextEncoder().encode(sample)).length);

結果:

    i: 0    char: 😀    bytes: 4    length: 2
    i: 1    char: œ    bytes: 2    length: 1
    i: 2    char: ´    bytes: 2    length: 1
    i: 3    char: ®    bytes: 2    length: 1
    i: 4    char: †    bytes: 3    length: 1
    i: 5    char: ¥    bytes: 2    length: 1
    i: 6    char: ¨    bytes: 2    length: 1
    i: 7    char: ˆ    bytes: 2    length: 1
    i: 8    char: ø    bytes: 2    length: 1
    i: 9    char: π    bytes: 2    length: 1
    i: 10    char: ¬    bytes: 2    length: 1
    i: 11    char: ˚    bytes: 2    length: 1
    i: 12    char: ∆    bytes: 3    length: 1
    i: 13    char: ˙    bytes: 2    length: 1
    i: 14    char: ©    bytes: 2    length: 1
    i: 15    char: ƒ    bytes: 2    length: 1
    i: 16    char: ∂    bytes: 3    length: 1
    i: 17    char: ß    bytes: 2    length: 1
    i: 18    char: å    bytes: 2    length: 1
    i: 19    char: Ω    bytes: 2    length: 1
    i: 20    char: ≈    bytes: 3    length: 1
    i: 21    char: ç    bytes: 2    length: 1
    i: 22    char: √    bytes: 3    length: 1
    i: 23    char: ∫    bytes: 3    length: 1
    i: 24    char: ˜    bytes: 2    length: 1
    i: 25    char: µ    bytes: 2    length: 1
    i: 26    char: ≤    bytes: 3    length: 1
    i: 27    char: ユ    bytes: 3    length: 1
    i: 28    char: ー    bytes: 3    length: 1
    i: 29    char: ザ    bytes: 3    length: 1
    i: 30    char: ー    bytes: 3    length: 1
    i: 31    char: コ    bytes: 3    length: 1
    i: 32    char: ー    bytes: 3    length: 1
    i: 33    char: ド    bytes: 3    length: 1
    i: 34    char: a    bytes: 1    length: 1
    total UTF-16 code units (erroneous calculation):  50
    total UTF-16 code units (correct calculation):    36
    total characters:                                 35
    total UTF-8 bytes:                                85
total number of UTF-16 code units:  36
total number of characters:         35
total number of UTF-8 bytes:        85

(另見 Jsfiddle: https ://jsfiddle.net/Allasso/o5zpmrc9/)

UTF-16 不同於 UTF-8。 00010000(十六進制)以下的所有 Unicode 字符都可以用單個 UTF-16 字符表示。 在此之上,您會溢出到 2 個 UTF-16 字符。 然而,這意味着所有 3 字節 UTF-8 編碼都適合單個 UTF-16 字符。

請記住,UTF-8 字符的 3 個字節並沒有完全用於實際的代碼點(數字)。 一些位被“標記”位占用,向解釋軟件指示代碼序列已經開始。 UTF-16 也是如此,但方案(標記位模式)不同。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM