概述
本文通過介紹Unicode編碼以及對應的兩種編碼方式UTF-8和UTF-16,讓讀者能夠了解關於字串編碼的相關知識,同時能夠弄清楚Unicode和UTF-8和UTF-16之間的關係。
本文的主要內容為:
- Unicode編碼,包含Unicode編碼基礎知識以及與UTF-8和UTF-16這兩種編碼方式的關係
- UTF-8編碼,包含基礎概念和Unicode編碼轉換到UTF-8編碼方式
- UTF-16編碼,包含基礎概念和Unicode編碼轉換到UTF-16編碼方式
- JavaScript中string與DOMString
本文作為utfx.js原始碼解析的基礎知識儲備文章,通過了解UTF-8和UTF-16這兩種編碼方式,讀者能夠理解使用JavaScript進行編碼轉換的原理。
如果想了解編碼轉換的使用場景,可以閱讀我之前的部落格WebSocket系列之JavaScript字串如何與二進位制資料間進行互相轉換。
如果想了解utfx.js相關的原始碼內容,可以關注我的後續文章。
Unicode編碼
概念
Unicode(統一碼、萬國碼、單一碼)是電腦科學領域裡的一項業界標準,包括字符集、編碼方案等。Unicode 是為了解決傳統的字元編碼方案的侷限而產生的,它為每種語言中的每個字元設定了統一併且唯一的二進位制編碼,以滿足跨語言、跨平臺進行文字轉換、處理的要求。1990年開始研發,1994年正式公佈。
通常Unicode編碼是通過2 Byte來表示一個字元的,如U+A12B
,2 Byte的二進位制表示方法結果就是1010(A)0001(1) 0010(2)1011(B)
。
簡單介紹完了Unicode,我們來看下UTF-8和UTF-16。需要注意的是:UTF是Unicode TransferFormat的縮寫,UTF-8和UTF-16都是把Unicode碼轉換成程式資料的一種編碼方式。
UTF-8
概念
UTF-8(8-bit Unicode Transformation Format)是一種針對Unicode的可變長度字元編碼,又稱萬國碼。由Ken Thompson於1992年建立。現在已經標準化為RFC 3629。UTF-8用1到6個位元組編碼Unicode字元。用在網頁上可以統一頁面顯示中文簡體繁體及其它語言(如英文,日文,韓文)。
通過上面的介紹我們可以知道,UTF-8是一種非常通用的可變長字元編碼方式。
首先,我們來介紹下什麼叫做可變長編碼?可變長編碼就是指在針對某個字元進行編碼時,他的表示長度是不固定的。像UTF-8裡面,ASCII所表示的字符集就是用1 Byte來表示,而大部分漢字則是用3 Byte來表示。
相較於Unicode統一使用2 Byte來表示字元,在遇到大部分字元都可以用1 Byte表示時,能夠節省許多儲存空間。但是,如果遇到需要用超過2 Byte來表示的字元,那麼UTF-8的編碼方式則會消耗更多的儲存空間。
表示方式
通過上面的介紹我們可以知道,不同的Unicode碼在UTF-8中佔用了不同的儲存空間。下面我們就通過一個表格來看下將Unicode字元轉換為UTF-8編碼方式的具體步驟。其中的?
表示轉換成UTF-8編碼後,Unicode碼佔用的二進位制位置。
Unicode碼範圍 | UTF-8編碼方式 |
---|---|
U+0000 ~U+007F |
0???????? |
U+0080 ~U+07FF |
110????? 10?????? |
U+0800 ~U+FFFF |
1110???? 10?????? 10?????? |
U+10000 ~U+10FFFF |
11110??? 10?????? 10?????? 10?????? |
當我們得到Unicode碼後,我們先根據上面的這個表判斷其所處的範圍,然後將Unicode碼轉換為二進位制表示,從後往前擷取UTF-8編碼中所留為之長度,從前往後依次填入對應位置,所即可得到UTF-8的編碼。我們舉兩個例子來看下:
U+0020
,這個字元的小於0000 007F,所以只需要用1 Byte來進行編碼。U+0020
的二進位制表示為0000(0)0000(0) 0010(2)0000(0)
,那麼從後往前擷取7位得到010 0000
,放入UTF-8編碼方式中,得到的結果為00101111
,轉換為十六進位制得到2F
。因此儲存在記憶體中的的順序就是2F
。U+A12B
,這個字元大於0000 0800,小於0000 FFFF,因此需要用3 Byte來進行編碼。U+A12B
的二進位制表示為1010(A)0001(1) 0010(2)1011(B)
。,那麼從後往前擷取16位得到10100001 00101011
(Unicode碼本身),放入UTF-8編碼中,得到的結果為11101010 10000100 10101011
,轉換十六進位制得到EA84AB
。因此,儲存在記憶體中的順序就是EA 84 AB
。
通過上面的例子,我相信大家對UTF-8的編碼有了一個深入的理解。下面,讓我們來看下另一種編碼方式——UTF-16。
UTF-16
概念
UTF-16是Unicode字元編碼五層次模型的第三層:字元編碼表(Character Encoding Form,也稱為 "storage format")的一種實現方式。即把Unicode字符集的抽象碼位對映為16位長的整數(即碼元, 長度為2 Byte)的序列,用於資料儲存或傳遞。Unicode字元的碼位,需要1個或者2個16位長的碼元來表示,因此這是一個變長表示。
引用維基百科中對於UTF-16編碼的解釋我們可以知道,UTF-16最少也會用2 Byte來表示一個字元,因此沒有辦法相容ASCII編碼(ASCII編碼使用1 Byte來進行儲存)。
表示方式
在UTF-16中,我們將Unicode分為了兩個範圍,分別通過不同的方式進行儲存。具體表示見下圖。
Unicode範圍 | UTF-16編碼方式 |
---|---|
U+000 ~U+FFFF |
2 Byte儲存,編碼後等於Unicode值 |
U+10000 ~U+10FFFF |
4 Byte儲存,現將Unicode值減去(0x10000),得到20bit長的值。再將Unicode分為高10位和低10位。UTF-16編碼的高位是2 Byte,高10位Unicode範圍為0 -0x3FF ,將Unicode值加上0XD800 ,得到高位代理(或稱為前導代理,儲存高位);低位也是2 Byte,低十位Unicode範圍一樣為0 ~0x3FF ,將Unicode值加上0xDC00 ,得到低位代理(或稱為後尾代理,儲存低位) |
根據上面的轉換方式,我們就能夠將Unicode碼根據UTF-16的編碼方式進行轉換。下面我們仍然通過兩個例子來看下:
U+0020
,這個值的範圍在第一部分,即經過UTF-16編碼後,結果仍然為U+0020
,在記憶體中的順序為00 20
。U+12345
, 這個值的範圍在第二部分,因此需要先減去0x10000
,得到0x02345
,拆分成高10位00 0000 1000
和低10位11 0100 0101
。根據上面規則加上特定值後,高位代理值為D808
,低位代理值為DF45
,最終記憶體中的順序為D8 08 DF 45
。
JavaScript中的string與DOMString
在JavaScript中,所有的string型別(或者被稱為DOMString)都是使用UTF-16編碼的。
因此,當我們需要轉換成二進位制與後端進行通訊時,需要注意相關的編碼方式。
總結
本文通過對Unicode編碼和UTF-8和UTF-16兩種編碼方式進行介紹,讓大家瞭解Unicode編碼以及相關的兩種程式資料編碼方式。
本文是作為utfx.js原始碼分析的基礎知識儲備文章,在稍後的時間將會給大家帶來相關內容的後續文章——utfx.js原始碼解析,讓大家能夠了解在JavaScript中如何進行相關的編碼轉換。