Unicode字符集的編碼方式以及碼點(diǎn)菩掏、碼元
一魂角、字符編碼方式CEF的選擇
1.
由于Unicode字符集非常大昵济,有些字符的編號(hào)(碼點(diǎn)值)需要兩個(gè)或兩個(gè)以上字節(jié)來(lái)表示,而要對(duì)這樣的編號(hào)進(jìn)行編碼野揪,也必須使用兩個(gè)或兩個(gè)以上字節(jié)访忿。
比如,漢字“嚴(yán)”的Unicode碼(Unicode碼點(diǎn)值斯稳、Unicode編號(hào))是十六進(jìn)制數(shù)4E25海铆,轉(zhuǎn)換成二進(jìn)制數(shù)有15位(100 1110 0010 0101),對(duì)“嚴(yán)”這個(gè)字符的編號(hào)進(jìn)行編碼的話挣惰,至少需要2個(gè)字節(jié)卧斟。表示其他更大編號(hào)的字符殴边,可能需要3個(gè)字節(jié)或者4個(gè)字節(jié),甚至更多珍语。
2.
這帶來(lái)兩個(gè)問(wèn)題:
一是锤岸,如何才能區(qū)別Unicode字符和ASCII字符的編碼?計(jì)算機(jī)怎么知道三個(gè)字節(jié)表示的是一個(gè)字符板乙,而不是分別表示三個(gè)字符呢是偷?
二是,我們知道募逞,英文字母只用一個(gè)字節(jié)來(lái)編碼就夠了蛋铆,而如果Unicode統(tǒng)一硬性規(guī)定,每個(gè)字符都用兩個(gè)放接、三個(gè)或四個(gè)字節(jié)來(lái)編碼刺啦,那么每個(gè)英文字母編碼的前面都必然有一個(gè)、兩個(gè)到三個(gè)字節(jié)全是0纠脾,這對(duì)于存儲(chǔ)和傳輸來(lái)說(shuō)是極大的浪費(fèi)洪燥。
這就涉及到了字符編碼方式CEF的選擇問(wèn)題。Unicode字符的編碼方式一般有三種:UFF-8乳乌、UTF-16捧韵、UTF-32。在具體介紹這些編碼方式之前汉操,需要再次深入了解兩個(gè)概念——碼點(diǎn)(Code Point)與碼元(Code Unit)再来。
二、碼點(diǎn)
1.
一個(gè)字符集一般可以用一張或多張由多個(gè)行和多個(gè)列所構(gòu)成的二維表來(lái)表示磷瘤。
二維表中行與列相交的點(diǎn)芒篷,稱之為碼點(diǎn)(Code Point代碼點(diǎn)),也稱之為碼位(Code position代碼位)采缚;每個(gè)碼點(diǎn)分配一個(gè)唯一的編號(hào)针炉,稱之為碼點(diǎn)值或碼點(diǎn)編號(hào),除開(kāi)某些特殊區(qū)域(比如代理區(qū)扳抽、專用區(qū))的非字符碼點(diǎn)和保留碼點(diǎn),每個(gè)碼點(diǎn)唯一對(duì)應(yīng)于一個(gè)字符贸呢。
因此镰烧,除開(kāi)非字符碼點(diǎn)和保留碼點(diǎn),碼點(diǎn)值(即碼點(diǎn)編號(hào))通常來(lái)說(shuō)就是其所對(duì)應(yīng)的字符的編號(hào)楞陷,所以碼點(diǎn)值有時(shí)也可以直接稱之為字符編號(hào)怔鳖,雖然不夠準(zhǔn)確,但更為直接固蛾。
2.
字符集中所有碼點(diǎn)數(shù)量的總和结执,稱之為編號(hào)空間(Code Space度陆,又被稱之為代碼空間、編碼空間献幔、碼點(diǎn)空間坚芜、碼空間)。
碼點(diǎn)值最初用兩個(gè)字節(jié)的十六進(jìn)制數(shù)字表示斜姥,比如字母A的Unicode碼點(diǎn)值為0041鸿竖,常寫作U+0041,這種形式稱為Unicode碼點(diǎn)名稱铸敏,不嚴(yán)格地來(lái)講缚忧,也可稱之Unicode字符名稱(因?yàn)榇嬖谥亲址a點(diǎn)和保留碼點(diǎn),并非每個(gè)碼點(diǎn)都分配了字符杈笔,所以這種稱呼不夠準(zhǔn)確闪水,不過(guò)目前更為普遍)。
3.
后來(lái)隨著Unicode字符集的不斷增補(bǔ)擴(kuò)大(比如現(xiàn)在的Unicode字符集至少需要21位才能全部表示)蒙具,碼點(diǎn)值也擴(kuò)展為用三個(gè)字節(jié)或以上的十六進(jìn)制數(shù)字表示球榆。
例如,ASCII字符集用0~127這連續(xù)的128個(gè)數(shù)字編號(hào)分別表示128個(gè)字符禁筏。GBK字符集使用區(qū)位碼的方式為每個(gè)字符編號(hào)持钉,首先定義一個(gè)94×94的矩陣,行稱為“區(qū)”篱昔,列稱為“位”每强,然后將所有國(guó)標(biāo)漢字放入矩陣當(dāng)中,這樣每個(gè)漢字就可以用唯一的“區(qū)位”碼來(lái)標(biāo)識(shí)了州刽。例如“中”字被放到54區(qū)第48位空执,因此其區(qū)位碼(字符編號(hào))就是5448。
而目前Unicode標(biāo)準(zhǔn)中穗椅,將字符按照一定的類別劃分到0~16這17個(gè)平面(Plane層面)中辨绊,每個(gè)平面中擁有2^16 = 65536個(gè)碼點(diǎn),因此匹表,目前Unicode字符集所擁有的碼點(diǎn)總數(shù)门坷,也就是Unicode的編號(hào)空間為17*65536=1114112。
注意桑孩,網(wǎng)絡(luò)上的很多文章中拜鹤,代碼點(diǎn)、碼點(diǎn)流椒、碼點(diǎn)值、碼值明也、代碼位宣虾、碼位惯裕、字符碼、Unicode碼绣硝、字符編號(hào)蜻势、字符編碼、編碼方案鹉胖、編碼方式握玛、編碼格式等等經(jīng)常互相代替混用甫菠。
(笨笨阿林原創(chuàng)文章挠铲,轉(zhuǎn)載請(qǐng)注明出處)
三、碼元
1.
在計(jì)算機(jī)存儲(chǔ)和網(wǎng)絡(luò)傳輸時(shí)寂诱,碼點(diǎn)值(即字符編號(hào))被映射到一個(gè)或多個(gè)碼元(Code Unit代碼單元拂苹、編碼單元)。
碼元可理解為字符編碼方式CEF(Character Encoding Form)對(duì)碼點(diǎn)值進(jìn)行編碼處理時(shí)作為一個(gè)整體來(lái)看待的最小基本單元(基本單位)痰洒。
2.
為什么非要引入“碼元”這個(gè)概念瓢棒?或者說(shuō),為什么非要強(qiáng)調(diào)“碼元”這個(gè)概念丘喻?
碼元某種程度上可認(rèn)為對(duì)應(yīng)于高級(jí)語(yǔ)言中的基本數(shù)據(jù)類型脯宿。而高級(jí)語(yǔ)言層面的基本數(shù)據(jù)類型,若要更深入一步地來(lái)講泉粉,實(shí)質(zhì)上對(duì)應(yīng)于機(jī)器硬件層面(匯編語(yǔ)言)的數(shù)據(jù)類型byte字節(jié)嗅绰、word字、dword雙字等在硬件中的表達(dá)與處理機(jī)制搀继。
之所以要強(qiáng)調(diào)“碼元”的概念窘面,是因?yàn)樽址幋a作為一串?dāng)?shù)字序列,最終還是得通過(guò)機(jī)器硬件層面的數(shù)據(jù)類型來(lái)表示叽躯。
而碼元的實(shí)質(zhì)财边,就是機(jī)器硬件層面(匯編語(yǔ)言)的數(shù)據(jù)類型;不同的碼元点骑,代表著不同位數(shù)的數(shù)據(jù)類型酣难。
3.
數(shù)據(jù)類型有單字節(jié)與多字節(jié)之分,所以碼元也有單字節(jié)與多字節(jié)之分黑滴;多字節(jié)數(shù)據(jù)類型由于歷史的原因憨募,存在著字節(jié)序的所謂大端序(Big-Endian)與小端序(Little-Endian)之分,因此多字節(jié)碼元也存在著大端序與小端序之分(具體詳見(jiàn)前文中有關(guān)字節(jié)序的解釋袁辈;注意菜谣,單字節(jié)數(shù)據(jù)類型則沒(méi)有字節(jié)序的問(wèn)題,所以單字節(jié)碼元也就沒(méi)有字節(jié)序問(wèn)題)。
這就是之所以要強(qiáng)調(diào)“碼元”這個(gè)概念的關(guān)鍵原因尾膊。
4.
碼點(diǎn)值(即字符編號(hào))的具體實(shí)現(xiàn)方式——字符編碼方式CEF媳危,就是由一個(gè)或多個(gè)碼元這樣的最小基本單元構(gòu)成的。
最常用的碼元是8位(1字節(jié))的單字節(jié)碼元冈敛,另外還有16位(2字節(jié))和32位(4字節(jié))兩種多字節(jié)碼元待笑,分別相當(dāng)于C++中的無(wú)符號(hào)整型BYTE、WORD抓谴、DWORD(在VC++6.0中暮蹂,這三種數(shù)據(jù)類型的定義分別為:
typedef unsigned char BYTE;,1個(gè)字節(jié)癌压;
typedef unsigned short WORD;仰泻,2個(gè)字節(jié);
typedef unsigned long DWORD;措拇,4個(gè)字節(jié))我纪。
(笨笨阿林原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明出處)
5.
于是丐吓,三種碼元對(duì)應(yīng)就有了Unicode字符編號(hào)(碼點(diǎn)值)的三種UTF編碼方式(即Unicode碼轉(zhuǎn)換格式Unicode Transformation Format浅悉,或稱通用字符集轉(zhuǎn)換格式UCS Transformation Format):
UTF-8(8-bit Unicode/UCS Transformation Format),
UTF-16(16-bit Unicode/UCS Transformation Format)券犁,
UTF-32(32-bit Unicode/UCS Transformation Format)术健;
或者反過(guò)來(lái)說(shuō),Unicode字符編號(hào)(碼點(diǎn)值)的三種UTF編碼方式(UTF-8粘衬、UTF-16荞估、UTF-32)分別采用了不同的碼元(BYTE、WORD稚新、DWORD)來(lái)編碼勘伺。
例如,“漢字”這兩個(gè)中文字符的Unicode碼點(diǎn)值(Unicode字符編號(hào))是0x6C49和0x5B57褂删,其三種UTF編碼在VC++6.0中可按如下定義進(jìn)行“模擬”:
?6.
注意飞醉,這里之所以說(shuō)是“模擬”,因?yàn)閺谋举|(zhì)上來(lái)講屯阀,在機(jī)器硬件層面上的所有數(shù)據(jù)類型缅帘,只存在著被視作一個(gè)整體來(lái)處理的比特序列(比特流)的位數(shù)不同之分,不存在著高級(jí)語(yǔ)言層面上數(shù)據(jù)類型的數(shù)值难衰、字符串钦无、布爾值等的語(yǔ)義不同之分。
因此盖袭,機(jī)器硬件層面上的數(shù)據(jù)類型與高級(jí)語(yǔ)言層面上的數(shù)據(jù)類型失暂,嚴(yán)格來(lái)講彼宠,在本質(zhì)含義上還是有著很大不同的。當(dāng)然趣席,高級(jí)語(yǔ)言層面上的數(shù)據(jù)類型最終還是會(huì)被轉(zhuǎn)化為機(jī)器硬件層面上的數(shù)據(jù)類型兵志,畢竟計(jì)算機(jī)只“認(rèn)識(shí)”由0和1所組成的比特流醇蝴。具體詳見(jiàn)前文中有關(guān)字節(jié)序的解釋宣肚。
7.
這里用BYTE、WORD悠栓、DWORD分別表示無(wú)符號(hào)8位整數(shù)霉涨、無(wú)符號(hào)16位整數(shù)和無(wú)符號(hào)32位整數(shù);因而UTF-8惭适、UTF-16笙瑟、UTF-32可認(rèn)為分別以BYTE、WORD癞志、DWORD作為碼元往枷。
“漢字”這兩個(gè)中文字符的UTF-8編碼需要六個(gè)BYTE(共6個(gè)單字節(jié)碼元),大小是6個(gè)字節(jié)凄杯;UTF-16編碼需要兩個(gè)WORD(共2個(gè)雙字節(jié)碼元)错洁,大小是4個(gè)字節(jié);UTF-32編碼需要兩個(gè)DWORD(共2個(gè)四字節(jié)碼元)戒突,大小是8個(gè)字節(jié)屯碴。
由于多字節(jié)數(shù)據(jù)類型的數(shù)據(jù)在計(jì)算機(jī)存取時(shí)存在一個(gè)字節(jié)序的問(wèn)題,因此膊存,UTF-16导而、UTF-32這兩種編碼方式所編碼出來(lái)的邏輯意義上的多字節(jié)碼元序列,在映射為物理意義上的字節(jié)序列時(shí)隔崎,字節(jié)序列的字節(jié)序因系統(tǒng)平臺(tái)的不同而不同今艺。
前面已經(jīng)多次強(qiáng)調(diào)過(guò)了,這里再次特別強(qiáng)調(diào)一下:由單字節(jié)數(shù)據(jù)類型所組成的多字節(jié)數(shù)據(jù)是不存在字節(jié)序的問(wèn)題的爵卒。因此虚缎,采用單字節(jié)碼元進(jìn)行編碼的UTF-8編碼,雖然ASCII字符為單字節(jié)編碼技潘,但非ASCII字符是多字節(jié)編碼的遥巴,但卻不存在字節(jié)序問(wèn)題,這是跟同樣為多字節(jié)編碼享幽、但采用多字節(jié)碼元的UTF-16铲掐、UTF-32不同之處。詳見(jiàn)下表所列:
?Unicode字符集三大編碼方式(UTF-8值桩、UTF-16摆霉、UTF-32)比較一覽表?
(笨笨阿林原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明出處)
?
【預(yù)告:下一篇將重點(diǎn)講解UTF-8編碼方式與字節(jié)序標(biāo)記(BOM),敬請(qǐng)關(guān)注携栋!】