碼元和碼點的區別

振锋小哥發表於2024-11-19

charCodeAt與codePointAt的用法:

相同點

  • charCodeAt與codePointAt都是字串例項上的方法,用途都是用來返回指定索引位字元的Unicode編碼。

不同點

  • charCodeAt與codePointAt匹配索引位的規則不一樣。charCodeAt是根據碼元來匹配,codePointAt是根據碼點來進行匹配的。

先舉個例子:



可以發現一個非常神奇的事情。

有些中文字元 𠮷 、 𪚥 的長度不為1,並且charCodeAtcodePointAt對相同字進行處理返回的結果卻是不同的。

這其中的原因就是charCodeAt是以一個碼元為一個索引,codePointAt是以一個碼點為一個索引進行處理的

Unicode使用16位二進位制來儲存文字。我們將一個16位的二進位制編碼叫做一個碼元(Code Unit),Unicode編碼範圍在0 - 2^16。也就是我們所說的佔2個位元組。

由於技術的發展,Unicode對文字編碼進行了擴充套件,將某些文字擴充套件到了32位(佔用兩個碼元),並且,將某個文字對應的二進位制數字叫做碼點(Code Point),Unicode編碼範圍在0 - 2^32,佔4個位元組。

特別要注意,碼點可以是一個碼元,也可以是兩個碼元。

字串的length屬性返回的是碼元。所以在對一些字串如果要處理長度的時候要注意這一點。

𠮷 這個字的Unicode編碼是 \ud842\udfb7,佔用了兩個碼元。

所以當用charCodeAt(0)是匹配0位的碼元,也就是返回給我們55362

當用codePointAt(0)是匹配0位的碼元,codePointAt能識別出字串的碼點,所以反回134071,反之將直接返回在那個索引處的編碼單元

𠮷.codePointAt(1)為什麼返回的是57271呢?

這是因為索引位是根據碼元,而匹配的規則是根據碼點的規則。如果後面兩位碼元是一個碼點,就會當作一個碼點來處理。

總結

charCodeAt是以碼元為單位來處理的,也就是說按照每16位2進位制數為單位。一個16位2進位制數就是一位,所以處理不了Unicode擴充套件編碼字元(32位2進位制)。他會把32位2進位制數當成兩個16位2進位制數處理

codePointAt也是以碼元位單位來處理的。與charCodeAt不同的地方是,當處理到當前位碼元時,如果超過了16位2進位制數值的上線,他就明白這是一個32位2進位制數,就會以32位2進位制數當作一個來處理。

可以透過codePointAt來判斷當前字元是是32位的(倆個碼元)還是16位的(單個碼元)

function is32bit(char, i) {
    //如果碼點大於了16位二進位制的最大值,則其是32位的
    return char.codePointAt(i) > 0xffff;
}

同樣的,也可以透過這個方法來判斷以字串真實的長度(碼點的長度)

function getLengthOfCodePoint(str) {
    var len = 0;
    for (let i = 0; i < str.length; i++) {
        //i在索引碼元
        if (is32bit(str, i)) {
            //當前字串,在i這個位置,佔用了兩個碼元
            i++;
        }
        len++;
    }
    return len;
}


相關文章