1. 程式人生 > >關於編碼之一:Unicode/UTF-8/UTF-16/UTF-32

關於編碼之一:Unicode/UTF-8/UTF-16/UTF-32

規則 系統默認 標記 大小端 post mark 編碼方式 一位 end

1.關於編碼,繞不開下面這些概念

①Unicode/UTF-8/UTF-16/UTF-32

②大小端字節序(big-endian/little-endian)

③BOM(Byte Order Mark)

2.關於Unicode/UTF-8/UTF-16/UTF-32

①Unicode其實應該是一個碼值表。(百度百科:Unicode的功用是為每一個字符提供一個唯一的代碼(即一組數字))。

②UTF-8/UTF-16/UTF-32是通過對Unicode碼值進行對應規則轉換後,編碼保持到內存/文件中。UTF-8/UTF-16/UTF-32都是可變長度的編碼方式。(後面將進行Unicode碼值轉換為UTF-8的說明)。

③我們平常說的 “Unicode編碼是2個字節” 這句話,其實是因為windows默認的Unicode編碼就是UTF-16,在常用基本字符上2個字節的編碼方式已經夠用導致的誤解,其實是可變長度的。

在沒有特殊說明的情況下,常說的Unicode編碼可以理解為UTF-16編碼。

④UTF-32是因為UTF-16編碼方式不能表示全部的字符而擴充的編碼方式。

ps:顯示的字符是表現形式,具體內存中的編碼方式和字符顯示之間通過中間層進行轉換。(根據編碼規則,1個字符可能對應內存中1個到幾個字節。)

3.UTF-8編碼

①UTF編碼方式,按照規則轉換後,第1個字節仍與ASCII兼容,這使得原來處理ASCII字符的軟件無須或只須做少部分修改,即可繼續使用。

網絡上數據傳輸英文字符只需要1個字節,可以節省帶寬資源。當前大部分的網絡應用都使用UTF-8編碼。(中文按照規則會轉換為3個字節,反而浪費資源,沒辦法,規則別人定好了!)

②UTF-8編碼需要進行字節數轉換+補碼兩個步驟

Unicode碼值轉UTF-8編碼規則之一(字節數轉換)

•1個字節:Unicode碼為0 - 127
•2個字節:Unicode碼為128 - 2047
•3個字節:Unicode碼為2048 - 0xFFFF
•4個字節:Unicode碼為65536 - 0x1FFFFF
•5個字節:Unicode碼為0x200000 - 0x3FFFFFF


•6個字節:Unicode碼為0x4000000 - 0x7FFFFFFF

Unicode碼值轉UTF-8編碼規則之二(二進制補碼)

對應上面規則一字節數轉換後,具體的補位碼如下,"x"表示空位,用來補位的,補不全則使用0。

可以看到規律,第一個字節前面有多少個1就表示占用多少個字節,紅色顏色位固定不變。(0-127的值直接使用0表示占用1個字節)

•1個字節:0xxxxxxx
•2個字節:110xxxxx 10xxxxxx
•3個字節:1110xxxx 10xxxxxx 10xxxxxx
•4個字節:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
•5個字節:111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
•6個字節:1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

③使用UTF-8編碼字符A

•字節數轉換:字符A的Unicode碼值為65,位於0-127的區間,所以占1個字節,其二進制值為1000001(7位)

•補碼:使用1個字節0xxxxxxx格式進行補碼(7個x),將上面的7位二進制值從右到左填到7個x中,得到01000001(8位)

得到字符A的UTF-8編碼為01000001(8位)

④使用UTF-8編碼中文字符“中”

•字節數轉換:中文字符“中”的Unicode碼值為20013,位於2048-0xFFFF的區間,所以占3個字節,其二進制值為1001110 00101101(15位)

•補碼:使用3個字節1110xxxx 10xxxxxx 10xxxxxx格式進行補碼(16個x),將上面的15位二進制值從右到左填到16個x中(不足位則將x變為0),得到11100100 10111000 10101101

得到中文字符“中的”UTF-8編碼位11100100 10111000 10101101(24位)

4.大小端字節序(big-endian/little-endian)

①字節序表示在內存/文件中字節的保存順序,由於硬件讀寫順序的不同,導致出現了大端和小端兩種方式。

大端:數據的高字節保存在內存的低地址中,低字節保存到內存的地址中,和我們的閱讀習慣一致;小端則相反,常用的X86結構是小端模式。

采用大端方式進行數據存放符合人類的正常思維,而采用小端方式進行數據存放利於計算機處理。

②UTF-8編碼不存在字節序大小端問題!(因為字節序只影響同時處理多於兩個字節的編碼方式,比如UTF-16/UTF-32,而UTF-8是按照單字節進行處理的)

UTF-8的解碼都必須先讀取首字節獲取字節數,所以必須找到首字節的第一位要麽是0,要麽是110/1110/11110/111110/1111110,所以上面的“中”字,無論是保存為11100100 10111000 10101101還是10101101 10111000 11100100,都必須要先找到11100100這個字節,所以UTF-8從機制上就能避免字節序的問題。

③UTF-16/UTF-32存在字節序問題(UTF-16常用情況下一次處理2個字節/UTF-32一次處理4個字節)!一個“奎”的Unicode碼值是0x594E,“乙”的Unicode碼值是0x4E59。如果我們的UTF-16字節數據是0x594E,那麽這是“奎”還是“乙”?如果大端序,0x594E是“奎”,如果是小端序,0x4E59,是“乙”。

5.BOM

①為了保證編碼和解碼字節順序問題(因為只有保證編碼和解碼的規則一致才能保證是同一個字符),所以Unicode規範中推薦的標記字節順序的方法是BOM(Byte Order Mark)。

②UTF-8不需要BOM來表明字節順序,但可以用BOM來表明編碼方式。根據BOM的規則,在一段字節流開始時,如果接收到以下字節,則分別表明了該文本文件的編碼。

UTF-8: EF BB BF

UTF-16 : FF FE

UTF-16 big-endian: FE FF

UTF-32 little-endian: FF FE 00 00

UTF-32 big-endian: 00 00 FE FF

而如果不是以這個開頭,那程序則會以ANSI,也就是系統默認編碼讀取。

如同樣是字符“A”﹐在以下幾種格式中的存儲形式分別是﹕

UTF-16 big-endian : 00 41

UTF-16 little-endian : 41 00

UTF-32 big-endian : 00 00 00 41

UTF-32 little-endian : 41 00 00 00

參考資料:

《為什麽utf-8沒有字節序問題?》

《UTF的字節序和BOM》

關於編碼之一:Unicode/UTF-8/UTF-16/UTF-32