Unicode與JavaScript詳解

阮一峰發表於2014-12-11

上個月,我做了一次分享,詳細介紹了Unicode字符集,以及JavaScript語言對它的支援。下面就是這次分享的講稿。

![](/blogimg/asset/2014/bg2014121102.jpg)

## 一、Unicode是什麼?

Unicode源於一個很簡單的想法:將全世界所有的字元包含在一個集合裡,計算機只要支援這一個字符集,就能顯示所有的字元,再也不會有亂碼了。

![](/blogimg/asset/2014/bg2014121103.jpg)

**它從0開始,為每個符號指定一個編號,這叫做"碼點"(code point)。**比如,碼點0的符號就是null(表示所有二進位制位都是0)。


U+0000 = null

上式中,U+表示緊跟在後面的十六進位制數是Unicode的碼點。

![](/blogimg/asset/2014/bg2014121115.png)

目前,Unicode的最新版本是7.0版,一共收入了109449個符號,其中的中日韓文字為74500個。可以近似認為,全世界現有的符號當中,三分之二以上來自東亞文字。比如,中文"好"的碼點是十六進位制的597D。


U+597D = 好

這麼多符號,Unicode不是一次性定義的,而是分割槽定義。每個區可以存放65536個(216)字元,稱為一個平面(plane)。目前,一共有17個(25)平面,也就是說,整個Unicode字符集的大小現在是221

最前面的65536個字元位,稱為基本平面(縮寫BMP),它的碼點範圍是從0一直到216-1,寫成16進位制就是從U+0000到U+FFFF。所有最常見的字元都放在這個平面,這是Unicode最先定義和公佈的一個平面。

剩下的字元都放在輔助平面(縮寫SMP),碼點範圍從U+010000一直到U+10FFFF。

![](/blogimg/asset/2014/bg2014121104.png)

## 二、UTF-32與UTF-8

Unicode只規定了每個字元的碼點,到底用什麼樣的位元組序表示這個碼點,就涉及到編碼方法。

**最直觀的編碼方法是,每個碼點使用四個位元組表示,位元組內容一一對應碼點。這種編碼方法就叫做UTF-32。**比如,碼點0就用四個位元組的0表示,碼點597D就在前面加三個位元組的0。


U+0000 = 0x0000 0000 0000 0000

U+597D = 0x0000 0000 0000 597D

![](/blogimg/asset/2014/bg2014121116.png)

UTF-32的優點在於,轉換規則簡單直觀,查詢效率高。缺點在於浪費空間,同樣內容的英語文字,它會比ASCII編碼大四倍。這個缺點很致命,導致實際上沒有人使用這種編碼方法,HTML 5標準就明文規定,網頁不得編碼成UTF-32。

![](/blogimg/asset/2014/bg2014121105.png)

人們真正需要的是一種節省空間的編碼方法,這導致了UTF-8的誕生。**UTF-8是一種變長的編碼方法,字元長度從1個位元組到4個位元組不等。**越是常用的字元,位元組越短,最前面的128個字元,只使用1個位元組表示,與ASCII碼完全相同。

編號範圍位元組
0x0000 - 0x007F1
0x0080 - 0x07FF2
0x0800 - 0xFFFF3
0x010000 - 0x10FFFF4

由於UTF-8這種節省空間的特性,導致它成為網際網路上最常見的網頁編碼。不過,它跟今天的主題關係不大,我就不深入了,具體的轉碼方法,可以參考我多年前寫的[《字元編碼筆記》](http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html)。

## 三、UTF-16簡介

UTF-16編碼介於UTF-32與UTF-8之間,同時結合了定長和變長兩種編碼方法的特點。

它的編碼規則很簡單:基本平面的字元佔用2個位元組,輔助平面的字元佔用4個位元組。**也就是說,UTF-16的編碼長度要麼是2個位元組(U+0000到U+FFFF),要麼是4個位元組(U+010000到U+10FFFF)。**

![](/blogimg/asset/2014/bg2014121106.png)

於是就有一個問題,當我們遇到兩個位元組,怎麼看出它本身是一個字元,還是需要跟其他兩個位元組放在一起解讀?

說來很巧妙,我也不知道是不是故意的設計,在基本平面內,從U+D800到U+DFFF是一個空段,即這些碼點不對應任何字元。因此,這個空段可以用來對映輔助平面的字元。

具體來說,輔助平面的字元位共有220個,也就是說,對應這些字元至少需要20個二進位制位。UTF-16將這20位拆成兩半,前10位對映在U+D800到U+DBFF(空間大小210),稱為高位(H),後10位對映在U+DC00到U+DFFF(空間大小210),稱為低位(L)。這意味著,一個輔助平面的字元,被拆成兩個基本平面的字元表示。

![](/blogimg/asset/2014/bg2014121117.png)

**所以,當我們遇到兩個位元組,發現它的碼點在U+D800到U+DBFF之間,就可以斷定,緊跟在後面的兩個位元組的碼點,應該在U+DC00到U+DFFF之間,這四個位元組必須放在一起解讀。**

## 四、UTF-16的轉碼公式

Unicode碼點轉成UTF-16的時候,首先區分這是基本平面字元,還是輔助平面字元。如果是前者,直接將碼點轉為對應的十六進位制形式,長度為兩位元組。


U+597D = 0x597D

如果是輔助平面字元,Unicode 3.0版給出了轉碼公式。


H = Math.floor((c-0x10000) / 0x400)+0xD800

L = (c - 0x10000) % 0x400 + 0xDC00

![](/blogimg/asset/2014/bg2014121107.png)

以字元

相關文章