UTF-8和unicode的關係

UTF-8和unicode的關係

結論:

Unicode是一種規範,UTF-8是具體的實現方式。
你可以這麼認爲,unicode就好比Java中的接口,它只規定一些規則和內容及表示方法,UTF-8是具體的實現,考慮了很多實際的東西,比如如何存儲、傳輸、解析、編碼。UTF-16、UTF-32也是具體的實現方式,每種實現都有一些有缺點的,各自適用的場景不同,一般我們最常用的就是UTF-8:

Unicode的多種實現:UTF-8、UTF-16、UTF-32;
UTF-8是我們最常接觸的,也是網絡上文件最流行的,因爲:採用UTF-8編碼後文本體積最小;
UTF-8 採用變長方式編碼文本;
UTF-8 存在:Big Endian和Little Endian問題,傳說主流是Little Endian
UTF-8 存在:帶BOM和不帶BOM的方式,一般推薦不帶BOM的文件

Unicode編碼規範

Unicode 是爲了解決傳統的字符編碼方案的侷限而產生的,它爲每種語言中的每個字符設定了統一併且唯一的二進制編碼,以滿足跨語言、跨平臺進行文本轉換、處理的要求。1990年開始研發,1994年正式公佈。

它是一種標準,規定了每個字符對應的二進制數,或者稱它是一個非常大的映射表。

但是unicode並沒有規定字符對應的二進制數怎麼存儲,比如字母可能對應的數字很小,那麼轉換爲二進制數需要8位(一個字節)就夠了。但是漢字就需要14/15/16位才能表示下也就是最少需要兩個字節,甚至有些字符需要三個字節才能表示。UTF-8、UTF-16、UTF-32的編碼單位不同,比如對“漢字”進行編碼和存儲:

  • UTF-8以8位爲一組計數,存儲“漢字”需要6個字節;
  • UTF-16以16位爲一組計數,存儲“漢字”需要4個字節;
  • UTF-32以32位爲一組,存儲“漢字”需要8個字節;

UTF-8的實現方式

UTF-8就是unicode的一種具體實現,它採用變長方式存儲字符,比如需要一個字節就可以表示的字符那就用一個字節存儲,需要二位字節表示的用兩個字節存儲。這樣就可以儘量縮短文件大小,方便文件存儲、傳輸。無用信息少了,文件就非常適合在網絡上傳輸,而且能佔用最少的磁盤空間。

UTF-8的編碼規則:

UTF-8的編碼規則很簡單,只有二條:

  • 對於單字節的符號(字符),字節的第一位設爲0,後面7位爲這個符號的unicode碼;因此對於英語字母,UTF-8編碼和ASCII碼是相同的;
  • 對於N字節的符號(N > 1),第一個字節的前N位都設爲1,第N + 1位設爲0,後面字節的前兩位一律設爲10,剩下的沒有提及的二進制位,全部爲這個符號的unicode碼。

下表是unicode(16進製表示)編碼時,對應的UTF-8編碼範圍。

Unicode編碼(十六進制) UTF-8編碼(二進制) UTF-8編碼大小(字節)
000000 - 00007F 0xxxxxxx 1
000080 - 0007FF 110xxxxx 10xxxxxx 2
000800 - 00FFFF 1110xxxx 10xxxxxx 10xxxxxx 3
010000 - 10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 4

跟據上表,解讀UTF-8編碼非常簡單:
* 先讀取第一個字節的第一位,如果是0,則讀取一個字節,0後的7位表示爲這個字符的編碼,通常用16進制顯示;
* 如果的第一個字節的第一位是1,則連續讀取直到爲0的位數,有多少個1,就表示當前字符佔用多少個字節,解碼的時候就讀取多少個字節,然後表示爲一個字符。

另外,當一個字符需要兩個以上字節表示時,比如漢字“中”的unicode編碼是 4E 2D,那麼具體存儲(傳輸)的時候是4E在前還是2D在前都是可以的,因此就產生了Little endian和Big endian。Little endian就是4E 2D的存儲,Big endian就是2D 4E的方式。

Big Endian 和 Little Endian

名稱由來

端模式(Endian)的這個詞出自Jonathan Swift書寫的《格列佛遊記》。故事裏面,小人國的人民對於吃雞蛋是從大頭敲開吃還是小頭敲開吃發生了爭論:主張從大頭敲開吃的被稱爲Big Endian;主張從小頭敲開吃的被稱爲Little Endian。兩派發生了激烈的整理,並因此引發了小人國的內戰。在計算機業Big Endian和Little Endian也幾乎引起一場戰爭。

Endian表示數據在存儲器中的存放順序;
採用大端方式進行數據存放符合人類的正常思維;
而採用小端方式進行數據存放利於計算機處理。

產生原因

具體的Big Endian和Little Endian的編解碼方式這裏不做解釋,有興趣的可以自行google。產生原因大致如下:

  • Big還是Little是由CPU引起的,涉及到兩大派系:Motorola的PowerPC系列CPU和Intel的x86系列CPU;
  • PowerPC系列採用Big Endian方式存儲數據,而Intel的x86系列則採用Little Endian方式存儲數據;
  • 一般來說,大部分操作系統(如windows,FreeBSD,Linux)是Little Endian的;
  • 少部分操作系統,如MAC OS是Big Endian的;

規律和建議

關於Big Endian和Little Endian到底哪個是正統哪個是旁系我們不做討論,只需要明白並注意一下幾點:

  • 所有網絡協議也都是採用Big Endian的方式來傳輸數據的。所以有時我們也會把Big endian方式稱之爲網絡字節序;
  • Java編寫的程序採用Big Endian方式來存儲數據;
  • 沒有統一建議,跟進自己的環境統一就好;
  • 有說Little Endian是主流的,估計是考慮PowerPC比較少見,而且Little Endian計算更快捷吧。

帶BOM和不帶BOM

BOM的全稱是Byte Order Mark,顧名思義就是字節序標記。BOM的設計本身是在UTF-8文件開頭存儲3個無意義的字節,這三個字節告訴編譯器這份文件使用的是unicode編碼,然後編譯器可以“智能“的調用文件解碼器,而不會產生亂碼問題;

BOM的歷史由來這裏不去深究了,而且也比較複雜,BOM並不是毫無用處的,有的時候沒有BOM是不行的,而且UTF-16、UTF-32也有BOM,UTF-16的BOM開頭是:FF FE。

最喜歡使用BOM的是微軟,它在自己的UTF-8格式的文本文件之前加上了EF BB BF三個字節,windows上面的notepad等程序就是根據這三個字節來確定一個文本文件是ASCII的還是UTF-8的,然而這個只是微軟暗自作的標記,其它平臺上並沒有對UTF-8文本文件做個這樣的標記。

關於BOM是好是壞的爭論,我們這裏不討論,路遙知馬力日久見人心,作爲普通的RD,不求甚解就好,在實際開發中建議:

1.儘量使用不帶BOM的UTF-8編碼方式,尤其是網頁,Unix不喜歡!;
2.微軟喜歡帶BOM的UTF-8,從微軟遷移文件的時候要注意,尤其是shell腳本;
3.把UTF-16稱爲unicode也是微軟特別喜歡的做法,儘量別這樣,把JVM稱爲Java總之是不合適的;
4.BOM並不是一無是處,不要一味的否定它,有的時候必須帶BOM;

如果想了解更多,可以自行百度,這類文章、磚家數不勝數,eg:
知乎-“帶BOM的UTF-8”和“無BOM的UTF-8”有什麼區別?網頁代碼一般使用哪個

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章