【转】刨根究底字符编码之十二——UTF-8究竟是怎么编码的
UTF-8究竟是怎么編碼的
1.
UTF-8編碼是Unicode字符集的一種字符編碼方式(CEF),其特點(diǎn)是使用變長(zhǎng)字節(jié)數(shù)(即變長(zhǎng)碼元序列或稱(chēng)變寬碼元序列)來(lái)編碼。目前一般是1到4個(gè)字節(jié),當(dāng)然,也可以更長(zhǎng)。
為什么要變長(zhǎng)呢?這可以理解為按需分配,比如一個(gè)字節(jié)足以容納所有的ASCII字符,那何必補(bǔ)一堆0,導(dǎo)致占用更多的字節(jié)來(lái)存儲(chǔ)呢?
實(shí)際上變長(zhǎng)編碼有其優(yōu)勢(shì),也有其劣勢(shì),優(yōu)勢(shì)方面除了上面所講的節(jié)省存儲(chǔ)空間之外,還有就是自動(dòng)糾錯(cuò)性能好、利于傳輸、擴(kuò)展性強(qiáng),而劣勢(shì)方面主要是由于字符的編碼字節(jié)數(shù)不固定導(dǎo)致不利于程序內(nèi)部處理,比如導(dǎo)致正則表達(dá)式檢索的復(fù)雜度大為增加;而UTF-32這樣的等長(zhǎng)碼元序列(即等寬碼元序列)的編碼方式就比較適合程序處理,當(dāng)然,缺點(diǎn)是比較耗費(fèi)存儲(chǔ)空間。
2.
那UTF-8究竟是怎么編碼的呢?也就是說(shuō)其編碼算法是什么?
UTF-8編碼最短的為一個(gè)字節(jié)、最長(zhǎng)的目前為四個(gè)字節(jié),從首字節(jié)就可以判斷一個(gè)UTF-8編碼有幾個(gè)字節(jié):
- 如果首字節(jié)以0開(kāi)頭,肯定是單字節(jié)編碼(即單個(gè)單字節(jié)碼元);
- 如果首字節(jié)以110開(kāi)頭,肯定是雙字節(jié)編碼(即由兩個(gè)單字節(jié)碼元所組成的雙碼元序列);
- 如果首字節(jié)以1110開(kāi)頭,肯定是三字節(jié)編碼(即由三個(gè)單字節(jié)碼元所組成的三碼元序列),以此類(lèi)推。
另外,UTF-8編碼中,除了單字節(jié)編碼外,由多個(gè)單字節(jié)碼元所組成的多字節(jié)編碼其首字節(jié)以外的后續(xù)字節(jié)均以10開(kāi)頭(以區(qū)別于單字節(jié)編碼以及多字節(jié)編碼的首字節(jié))。
0、110、1110以及10相當(dāng)于UTF-8編碼中各個(gè)字節(jié)的前綴,因此稱(chēng)之為前綴碼。其中,前綴碼110、1110及10中的0,是前綴碼中的終結(jié)標(biāo)志。
UTF-8編碼中的前綴碼起到了很好的區(qū)分和標(biāo)識(shí)的作用:
- 當(dāng)解碼程序讀取到一個(gè)字節(jié)的首位為0,表示這是一個(gè)單字節(jié)編碼的ASCII字符;
- 當(dāng)讀取到一個(gè)字節(jié)的首位為1,表示這是一個(gè)非ASCII字符的多字節(jié)編碼字符中的某個(gè)字節(jié)(可能是首字節(jié),也可能是后續(xù)字節(jié)),接下來(lái)若繼續(xù)讀取到一個(gè)1,則確定為首字節(jié),再繼續(xù)讀取直到遇見(jiàn)終結(jié)標(biāo)志0為止,讀取了幾個(gè)1,就表示該字符為幾個(gè)字節(jié)的編碼;
- 當(dāng)讀取到一個(gè)字節(jié)的首位為1,緊接著讀取到一個(gè)終結(jié)標(biāo)志0,則該字節(jié)顯然是非ASCII字符的后續(xù)字節(jié)(即非首字節(jié))。
(笨笨阿林原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明出處)
3.
所以,1~4字節(jié)的UTF-8編碼看起來(lái)分別是這樣的:
單字節(jié)可編碼的Unicode碼點(diǎn)值范圍十六進(jìn)制為0x0000 ~ 0x007F,十進(jìn)制為0 ~ 127;
雙字節(jié)可編碼的Unicode碼點(diǎn)值范圍十六進(jìn)制為0x0080 ~ 0x07FF,十進(jìn)制為128 ~ 2047;
三字節(jié)可編碼的Unicode碼點(diǎn)值范圍十六進(jìn)制為0x0800 ~ 0xFFFF,十進(jìn)制為2048 ~ 65535;
四字節(jié)可編碼的Unicode碼點(diǎn)值范圍十六進(jìn)制為0x10000 ~ 0x1FFFFF,十進(jìn)制為65536 ~ 2097151(目前Unicode字符集碼點(diǎn)編號(hào)的最大值為0x10FFFF,實(shí)際尚未編號(hào)到0x1FFFFF;這說(shuō)明作為變長(zhǎng)字節(jié)數(shù)的UTF-8編碼其未來(lái)擴(kuò)展性非常強(qiáng),即便目前的四字節(jié)編碼也還有大量編碼空間未被使用,更不論還可擴(kuò)展為五字節(jié)、六字節(jié)……)。
(笨笨阿林原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明出處)
4.
上述Unicode碼點(diǎn)值范圍中十進(jìn)制值127、2047、65535、2097151這幾個(gè)臨界值是怎么來(lái)的呢?
因?yàn)閁TF-8編碼中的每個(gè)字節(jié)中都含有起到區(qū)分和標(biāo)識(shí)之用的前綴碼0、110、1110以及10之一,所以1~4個(gè)字節(jié)的UTF-8編碼其實(shí)際有效位數(shù)分別為8-1=7位(2^7-1=127)、16-5=11位(2^11-1=2047)、24-8=16位(2^16-1=65535)、32-11=21位(2^21-1=2097151),如下表所示:
注:上圖中的Unicode range為Unicode碼點(diǎn)值范圍(也就是Unicode碼點(diǎn)編號(hào)范圍),Hex為16進(jìn)制,Binary為二進(jìn)制;Encoded bytes為UTF-8編碼中各字節(jié)的編碼方式(即編碼算法),其中,x代表Unicode二進(jìn)制碼點(diǎn)值的單字節(jié)或低字節(jié)中的低7位或8位、y代表兩字節(jié)碼點(diǎn)值的高字節(jié)中的低3位或8位以及三字節(jié)碼點(diǎn)值的中字節(jié)中的8位、z代表三字節(jié)碼點(diǎn)值的高字節(jié)中的低5位。
因此,UTF-8編碼的算法簡(jiǎn)單地來(lái)概括就是:首先確定UTF-8編碼中各個(gè)字節(jié)的前綴碼;之后再將UTF-8編碼中各個(gè)字節(jié)除了前綴碼所占用之外的位,依次分配給Unicode字符碼點(diǎn)值二進(jìn)制中各個(gè)位的值。換言之,就是用Unicode字符碼點(diǎn)值二進(jìn)制中各個(gè)位的值,依次填充UTF-8編碼中的各個(gè)字節(jié)除了前綴碼所占用之外的位。
5.
由于ASCII字符的UTF-8編碼使用單字節(jié),而且和ASCII編碼一模一樣,這樣所有原先使用ASCII編碼的文檔就可以直接解碼了,無(wú)需進(jìn)行任何轉(zhuǎn)換,實(shí)現(xiàn)了完全兼容。考慮到計(jì)算機(jī)世界里的英文文檔數(shù)量之多,這一點(diǎn)意義重大。
而對(duì)于其他非ASCII字符,則使用2~4個(gè)字節(jié)的編碼來(lái)表示。其中,首字節(jié)中前置的“1”的個(gè)數(shù)代表該字符編碼的字節(jié)數(shù)(如110代表兩個(gè)字節(jié)、1110代表三個(gè)字節(jié),以此類(lèi)推),非首字節(jié)之外的剩余后續(xù)字節(jié)的前兩位始終是10,這樣就不會(huì)與ASCII字符編碼(“0”開(kāi)頭)以及非ASCII字符的首字節(jié)編碼(110或1110等至少兩個(gè)“1”開(kāi)頭)相沖突。
例如,假設(shè)某個(gè)字符的首字節(jié)是1110yyyy,前置有三個(gè)1,說(shuō)明該字符編碼總共有三個(gè)字節(jié),必須和后面兩個(gè)以10開(kāi)頭的字節(jié)結(jié)合才能正確解碼該字符。
6.
由此可知,UTF-8編碼設(shè)計(jì)得非常精巧,雖說(shuō)不上完美無(wú)瑕,但若與后文將要介紹的UTF-16、UTF-32以及前文介紹過(guò)的那些ANSI編碼相比較,對(duì)于其精巧設(shè)計(jì)將體會(huì)得更為深切透徹。因此,UTF-8越來(lái)越得到全球一致認(rèn)可,大有一統(tǒng)字符編碼之勢(shì)。
(笨笨阿林原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明出處)
(未完待續(xù))
【預(yù)告:本系列文章下一篇將重點(diǎn)介紹UTF-16編碼,敬請(qǐng)關(guān)注!】
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的【转】刨根究底字符编码之十二——UTF-8究竟是怎么编码的的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【转】ABP源码分析三十一:ABP.Au
- 下一篇: 手机就能穿越历史!腾讯宣布将复现敦煌藏经