一、Unicode是什么?
Unicode(統一碼、萬國碼、單一碼)是計算機科學領域里的一項業界標准,包括字符集、編碼方案等。Unicode 是為了解決傳統的字符編碼方案的局限而產生的,它為每種語言中的每個字符設定了統一並且唯一的二進制編碼,以滿足跨語言、跨平台進行文本轉換、處理的要求。1990年開始研發,1994年正式公布。
最早的字符編碼是ASCII碼,每個字符是通過一個字節來表示的,但是隨着計算機的不斷發展,許多文字並不能用一個字節來表示,為了能夠表示更多的語言文字,所以產生了Unicode,用兩個字節來對字符進行編碼,這樣的話像中文、日語等也能夠成功的在計算機上顯示並且保存。在表示一個Unicode的字符時,通常會用“U+”然后緊接着一組十六進制的數字來表示這一個字符。
二、UTF8/16/32分別是什么?
1) UTF8:UTF-8以字節為單位對Unicode進行編碼。從Unicode到UTF-8的編碼方式如下:
Unicode編碼(十六進制) |
UTF-8 字節流(二進制) |
000000-00007F |
0xxxxxxx |
000080-0007FF |
110xxxxx 10xxxxxx |
000800-00FFFF |
1110xxxx 10xxxxxx 10xxxxxx |
010000-10FFFF |
11110xxx10xxxxxx10xxxxxx10xxxxxx |
UTF-8的特點:是對不同范圍的字符使用不同長度的編碼。對於0x00-0x7F之間的字符,UTF-8編碼與ASCII編碼完全相同。UTF-8編碼的最大長度是4個字節。從上表可以看出,4字節模板有21個x,即可 以容納21位二進制數字。Unicode的最大碼位0x10FFFF也只有21位。
2)UTF16:UTF-16是Unicode字符編碼五層次模型的第三層:字符編碼表(Character Encoding Form,也稱為 "storage format")的一種實現方式。即把Unicode字符集的抽象碼位映射為16位長的 整數(即碼元)的序列,用於數據存儲或傳遞。Unicode字符的碼位,需要1個或者2個16位長的碼元來表示,因此這是一個變長表示。
3)UTF32:UTF-32 (或 UCS-4)是一種將Unicode字符編碼的協定,對每一個Unicode碼位使用恰好32位元。其它的Unicode transformation formats則使用不定長度編碼。因為UTF-32對每個字符都 使用4字節,就空間而言,是非常沒有效率的。特別地,非基本多文種平面的字符在大部分文件中通常很罕見,以致於它們通常被認為不存在占用空間大小的討論,使得UTF-32通常會是其它 編碼的二到四倍。雖然每一個碼位使用固定長定的字節看似方便,它並不如其它Unicode編碼使用得廣泛。
三、Unicode和UTF8/16/32之間的關系
首先要注意的是unicode是編碼字符集,而UTF-8、UTF-16、UTF-32是字符集編碼。下面我來具體解釋一下:比如漢字的”漢”,在unicode中,漢”的unicode值為0x6C49。問:把這個”漢”字保存到計算機中(硬盤、內存),機器碼是多少呢? 學過《計算機組成原理》的人都知道,計算機內部存儲的形式都是0101的二進制數字串。”漢”字保存在計算機里肯定也是0101的數字串。”漢”的unicode值是0x6C49,轉化為2進制 1101100 01001001,那么把這個”漢”字保存到計算機中也是 1101100 01001001 嗎?其實並不是這樣的,答案取決於用到的字符集編碼是哪種 比如你用到的字符集編碼是UTF-8,那么”漢”字在計算機內部保存的值為0xE6B189,也就是111001101011000110001001,可以看到”漢”字變成了3個字節。UTF-8用1-4個字節來保存unicode編碼的字符。 而如果用UTF-16來保存,那么”漢”字仍為仍為0x6C49,也就是 1101100 01001001。UTF-16只能是選兩字節或四字節來保存字符 而UTF-32就是把所有的字符都用32bit也就是4個字節來表示。 所以這就是編碼字符集和字符集編碼的區別。
UTF,即Unicode Transformer Format,是Unicode代碼點(code point)的實際表示方式,按其基本長度所用位數分為UTF-8/16/32。它也可以認為是一種特殊的外部數據編碼,但能夠與Unicode代碼點做一一對應。也就是其實從本質上說,UTF-8、UTF-16、UTF-32 都是 Unicode 的一種實現,只是實現的方式不同罷了。所以UTF8/16/32是Unicode的衍生,和Unicode是息息相關的。接下來從這三個UTF開始分析和Unicode的關系。
1、UTF-32
這個就是字符所對應編號的整數二進制形式,四個字節。這個就是直接轉換。 比如馬的 Unicode 為:U+9A6C,那么直接轉化為二進制,它的表示就為:1001 1010 0110 1100。
這里需要說明的是,轉換成二進制后計算機存儲的問題,我們知道,計算機在存儲器中排列字節有兩種方式:大端法和小端法,大端法就是將高位字節放到低地址處,比如 0x1234, 計算機用兩個字節存儲,一個是高位字節 0x12,一個是低位字節 0x34,它的存儲方式為下:
UTF-32 用四個字節表示,處理單元為四個字節(一次拿到四個字節進行處理),如果不分大小端的話,那么就會出現解讀錯誤,比如我們一次要處理四個字節 12 34 56 78,這四個字節是表示 0x12 34 56 78 還是表示 0x78 56 34 12?不同的解釋最終表示的值不一樣。
我們可以根據他們高低字節的存儲位置來判斷他們所代表的含義,所以在編碼方式中有 UTF-32BE 和 UTF-32LE,分別對應大端和小端,來正確地解釋多個字節(這里是四個字節)的含義。
UTF-16 使用變長字節表示
① 對於編號在 U+0000 到 U+FFFF 的字符(常用字符集),直接用兩個字節表示。
② 編號在 U+10000 到 U+10FFFF 之間的字符,需要用四個字節表示。
同樣,UTF-16 也有字節的順序問題(大小端),所以就有 UTF-16BE 表示大端,UTF-16LE 表示小端。
UTF-8 就是使用變長字節表示,顧名思義,就是使用的字節數可變,這個變化是根據 Unicode 編號的大小有關,編號小的使用的字節就少,編號大的使用的字節就多。使用的字節個數從 1 到 4 個不等。
UTF-8 的編碼規則是:
① 對於單字節的符號,字節的第一位設為 0,后面的7位為這個符號的 Unicode 碼,因此對於英文字母,UTF-8 編碼和 ASCII 碼是相同的。
② 對於n字節的符號 (n>1),第一個字節的前 n 位都設為 1,第 n+1 位設為 0,后面字節的前兩位一律設為 10,剩下的沒有提及的二進制位,全部為這個符號的 Unicode 碼 。
舉個例子:比如說一個字符的 Unicode 編碼是 130,顯然按照 UTF-8 的規則一個字節是表示不了它(因為如果是一個字節的話前面的一位必須是 0),所以需要兩個字節(n = 2)。
根據規則,第一個字節的前 2 位都設為 1,第 3(2+1) 位設為 0,則第一個字節為:110X XXXX,后面字節的前兩位一律設為 10,后面只剩下一個字節,所以后面的字節為:10XX XXXX。
所以它的格式為 110XXXXX 10XXXXXX 。
下面我們來具體看看具體的 Unicode 編號范圍與對應的 UTF-8 二進制格式
那么對於一個具體的 Unicode 編號,具體怎么進行 UTF-8 的編碼呢?
首先找到該 Unicode 編號所在的編號范圍,進而可以找到與之對應的二進制格式,然后將該 Unicode 編號轉化為二進制數(去掉高位的 0),最后將該二進制數從右向左依次填入二進制格式的 X 中,如果還有 X 未填,則設為 0 。
比如:“馬”的 Unicode 編號是:0x9A6C,整數編號是 39532,對應第三個范圍(2048 - 65535),其格式為:1110XXXX 10XXXXXX 10XXXXXX,39532 對應的二進制是 1001 1010 0110 1100,將二進制填入進去就為:
11101001 10101001 10101100 。
由於 UTF-8 的處理單元為一個字節(也就是一次處理一個字節),所以處理器在處理的時候就不需要考慮這一個字節的存儲是在高位還是在低位,直接拿到這個字節進行處理就行了,因為大小端是針對大於一個字節的數的存儲問題而言的。
從上面的講解也能看出來,UTF8/16/32都是Unicode的一種實現方式。