Unicode 和 UTF-8 、UTF-16是什么關(guān)系呢忍啤?這是我最近好奇的一個(gè)問題加勤。
Unicode
Unicode 是計(jì)算機(jī)科學(xué)領(lǐng)域里的一項(xiàng)業(yè)界標(biāo)準(zhǔn),包括字符集(包含來自世界各國各地的文字字符)和編碼方案(將每個(gè)字符唯一映射到一個(gè)二進(jìn)制編碼)檀轨。
Unicode 編碼方式
Unicode 的基本元素是碼位(code point)胸竞,共包含1114112個(gè)碼位。碼位通過使用數(shù)值表示参萄,數(shù)值格式為:U+hhhh卫枝,其中每個(gè)h代表一個(gè)十六進(jìn)制數(shù)字。
Unicode 的所有碼位組成了一個(gè)編碼空間讹挎。在Unicode編碼空間校赤,Unicode碼位分為17組編排,每組稱為平面(Plane)筒溃,而每平面擁有65536個(gè)碼位马篮。如下圖所示:
Unicode 遵守既定規(guī)則把世界上的字符一一映射到碼位中。被使用的碼位怜奖,其碼點(diǎn)值就是對應(yīng)字符的Unicode編碼浑测。如, U+0041 表示拉丁字母 “A”歪玲;U+40000 由于沒使用迁央,不表示任何字符。
截止目前滥崩,才128237 個(gè)碼位被使用——編碼空間的 12% 被賦值岖圈,在后面還有很多空間可應(yīng)對新出現(xiàn)的字符。
Unicode 實(shí)現(xiàn)方式
Unicode 規(guī)定了字符的編碼钙皮,但是沒有規(guī)定如何實(shí)現(xiàn)字符的編碼蜂科。實(shí)現(xiàn)編碼的方式稱為Unicode 轉(zhuǎn)換格式(Unicode Transformation Format,簡稱為UTF)短条。
Unicode 編碼范圍從 U+0000 到 U+10FFFF导匣。對于計(jì)算機(jī)而言,實(shí)現(xiàn)Unicode 編碼的最簡單方式是使用32-bit表示茸时。但是每個(gè)字符使用4個(gè)字節(jié)表示會造成浪費(fèi)贡定。當(dāng)你處理大量文本的時(shí)候,使用 32-bit 存儲 Unicode 字符會占用大量額外存儲屹蚊、內(nèi)存厕氨、帶寬等,因?yàn)榇蠖嘧址牡?和第2個(gè)字節(jié)都是0汹粤。
在日常命斧,Unicode編碼的實(shí)現(xiàn)方式主要有:UTF-8、UTF-16嘱兼。
UTF-8
UTF-8是一種可變長度字符編碼方式国葬,以8-bit 為單元,使用1至4個(gè)字節(jié)為每個(gè)字符編碼芹壕。
UTF-8編碼規(guī)則如下:
Unicode編碼范圍 (十六進(jìn)制) | UTF-8編碼占用字節(jié) | UTF-8 編碼(二進(jìn)制) |
---|---|---|
U+0000 - U+007F | 1 | 0xxxxxxx |
U+0080 - U+07FF | 2 | 110xxxxx 10xxxxxx |
U+0800 - U+FFFF | 3 | 1110xxxx 10xxxxxx 10xxxxxx |
U+10000 - U+10FFFF | 4 | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
根據(jù)字符所在編碼范圍汇四,確定其所占字節(jié)數(shù)
單字節(jié)的字符,字節(jié)的第一位設(shè)為0
n個(gè)字節(jié)的字符(n>1)踢涌,第一個(gè)字節(jié)的前n位設(shè)為1通孽,第n+1位設(shè)為0,后面字節(jié)的前兩位都設(shè)為10睁壁,這n個(gè)字節(jié)的其余空位填充該字符unicode碼背苦,高位用0補(bǔ)足
下面,以漢字“魚”為例潘明,演示如何實(shí)現(xiàn)UTF-8編碼行剂。
“魚”的Unicode編碼是9C7C
(1001 1100 0111 1100
),根據(jù)上表钳降,9C7C
的UTF-8編碼需要占用3個(gè)字節(jié)厚宰,其格式為1110xxxx 10xxxxxx 10xxxxxx
。然后遂填,從“魚”的最后一個(gè)二進(jìn)制位開始铲觉,依次從后向前填入格式中的x
,多出的位補(bǔ)0
城菊。這樣备燃,就得到“魚”的UTF-8編碼:11101001 10110001 10111100
,轉(zhuǎn)換為十六進(jìn)制就是:E9B1BC
UTF-16
UTF-16是一種可變長度字符編碼方式凌唬,以16-bit 為單元并齐,使用2個(gè)或4個(gè)字節(jié)為每個(gè)字符編碼。
UTF-16的編碼規(guī)則如下:
Unicode編碼范圍 (十六進(jìn)制) | UTF-16編碼占用字節(jié) | UTF-16 編碼(二進(jìn)制) |
---|---|---|
U+0000 - U+FFFF | 2 | xxxxxxxx xxxxxxxx |
U+10000 - U+10FFFF | 4 | 110110yyyyyyyyyy 110111xxxxxxxxxx |
把字符的Unicode編碼記作 U
若U < 0x10000客税,字符的UTF-16編碼就是U對應(yīng)的16位二進(jìn)制:xxxxxxxx xxxxxxxx
若U ≥ 0x10000况褪,則把字符拆分為2部分(U+10000 ~ U+10FFFF的空間大小是2^20),前十位映射到U+D800U+DBFF更耻,后十位映射到U+DC00U+DFFF测垛。具體拆分計(jì)算如下:
計(jì)算U'=U-0x10000,
將U'寫成二進(jìn)制形式:yyyy yyyy yyxx xxxx xxxx,
按照
110110yyyyyyyyyy 110111xxxxxxxxxx
格式填入跋破,即得到U的UTF-16編碼(二進(jìn)制):110110yyyyyyyyyy 110111xxxxxxxxxx
- 在基本平面(0x00000xFFFF)內(nèi),U+D800U+DFFF是一個(gè)空段青扔,即這些碼位不對應(yīng)任何字符
- 輔助平面(0x10000~0x10FFFF)的字符位共有2^20個(gè)
- U+D800U+DBFF锯七,空間大小是2^10链快;U+DC00U+DFFF,空間大小是2^10眉尸。二者組合起來域蜗,正好可以表示輔助平面的字符。即:輔助平面的字符可以拆分為兩個(gè)基本平面的字符表示——字符前10位映射在U+D800到U+DBFF噪猾,后10位映射在U+DC00到U+DFFF
下面霉祸,以漢字“魚”和字符“??”為例,演示如何實(shí)現(xiàn)UTF-16編碼袱蜡。
“魚”的Unicode編碼是9C7C
丝蹭,根據(jù)上表,9C7C < 0x10000
戒劫,其UTF-16編碼就是其Unicode編碼:1001 1100 0111 1100
半夷,即0x9C7C。
“??”的Unicode編碼是1D300
迅细,根據(jù)上表巫橄,1D300 > 0x10000
,然后減去0x10000茵典,得到0xD300湘换,按yyyy yyyy yyxx xxxx xxxx
格式寫成二進(jìn)制是:0000 1101 0011 0000 0000
,然后按照110110yyyyyyyyyy 110111xxxxxxxxxx
格式填入统阿,得到“??”的UTF-16編碼(二進(jìn)制):1101100000110100 1101111100000000
彩倚,即0xD834 0xDF00
。
結(jié)論
回到先前的疑問:Unicode 和 UTF-8 扶平、UTF-16是什么關(guān)系呢帆离?
打個(gè)比喻,它們理論和實(shí)現(xiàn)的關(guān)系:Unicode制定了的理論结澄,UTF-8和UTF-16是具體的實(shí)現(xiàn)方案哥谷。
而更形象的比喻則是:Unicode相當(dāng)于中文, UTF-8、 UTF-16等相當(dāng)于 行書麻献、 楷書们妥、草書等各種書寫方式。
參考資料:
https://zh.wikipedia.org/wiki/Unicode
https://zh.wikipedia.org/wiki/UTF-8
https://zh.wikipedia.org/wiki/UTF-16
http://www.ruanyifeng.com/blog/2014/12/unicode.html
http://blog.jobbole.com/111261/
http://blog.csdn.net/softman11/article/details/6124345
https://www.zhihu.com/question/23374078