iOS - Unicode編碼


一、來歷

 

為了統一編碼,各大龍頭企業就決定坐下來對全世界的字符進行編碼,並且盡量兼容現有字符集,這就有了unicode編碼。Unicode用了21個二進制位,能夠編碼一百多萬個字符,但實際上並沒有編碼這么多。U+XXXX中XXXX就是碼點,就是字符在unicode的數字表示。

編碼空間被分成 17 個平面(plane),每個平面有 65,536 個字符。0 號平面叫做「基本多文種平面」(Basic Multilingual Plane, BMP),涵蓋了幾乎所有你能遇到的字符,除了 emoji。其它平面叫做補充平面,大多是空的。

 

二、UTF-32、UTF-16、UTF-8

 

什么字符被表示成什么樣子的規定有了,就要考慮怎么存起來了,這就分成了UTF-32、UTF-16、UTF-8三種了。所以UTF-32、UTF-16、UTF-8只是unicode的三種實現方式。

 

三、UTF-32

 

unicode用了21位,那我就用4個字節存,准錯不了,這就是UTF-32,由於它的極度浪費,所以基本上沒人用。

 

四、UTF-16

 

UTF-16編碼介於UTF-32與UTF-8之間,同時結合了定長和變長兩種編碼方法的特點。UTF-16把字符存儲成2個字節或者4個字節。

具體如下:
基本平面的字符占用2個字節,輔助平面的字符占用4個字節。也就是說,UTF-16的編碼長度要么是2個字節(U+0000到U+FFFF),要么是4個字節(U+010000到U+10FFFF)。

於是就有一個問題,當我們遇到兩個字節,怎么看出它本身是一個字符,還是需要跟其他兩個字節放在一起解讀?

說來很巧妙,我也不知道是不是故意的設計,在基本平面內,從U+D800到U+DFFF是一個空段,即這些碼點不對應任何字符。因此,這個空段可以用來映射輔助平面的字符。

具體來說,輔助平面的字符位共有2的20次方個,也就是說,對應這些字符至少需要20個二進制位。UTF-16將這20位拆成兩半,前10位映射在U+D800到U+DBFF(空間大小210),稱為高位(H),后10位映射在U+DC00到U+DFFF(空間大小210),稱為低位(L)。這意味着,一個輔助平面的字符,被拆成兩個基本平面的字符表示。

 

五、相當巧妙的UTF-8

 

UTF-8最大的一個特點,就是它是一種變長的編碼方式。它可以使用1~4個字節表示一個符號,根據不同的符號而變化字節長度。

UTF-8的編碼規則很簡單,只有二條:
1)對於單字節的符號,字節的第一位設為0,后面7位為這個符號的unicode碼。因此對於英語字母,UTF-8編碼和ASCII碼是相同的。
2)對於n字節的符號(n>1),第一個字節的前n位都設為1,第n+1位設為0,后面字節的前兩位一律設為10。剩下的沒有提及的二進制位,全部為這個符號的unicode碼。

 

Unicode符號范圍 | UTF-8編碼方式
(十六進制) | (二進制)
--------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx


舉例說明:
已知\"嚴\"的unicode是4E25(100111000100101),根據上表,可以發現4E25處在第三行的范圍內(0000 0800-0000 FFFF),因此\"嚴\"的UTF-8編碼需要三個字節,即格式是\"1110xxxx 10xxxxxx 10xxxxxx\"。然后,從\"嚴\"的最后一個二進制位開始,依次從后向前填入格式中的x,多出的位補0。這樣就得到了,\"嚴\"的UTF-8編碼是\"11100100 10111000 10100101”,轉換成十六進制就是E4B8A5。

由於大學學習離散數學時有一種變長的編碼方式,受其影響太大,對於UTF-8的編碼方式一度覺得不可思議,現在來看原來如此~

 

六、UTF-16的大頭、小頭問題

 

Unicode碼是4E25,需要用兩個字節存儲,一個字節是4E,另一個字節是25。存儲的時候,4E在前,25在后,就是Big endian方式;25在前,4E在后,就是Little endian方式。

unicode規范中定義,每一個文件的最前面分別加入一個表示編碼順序的字符,這個字符的名字叫做\"零寬度非換行空格\"(ZERO WIDTH NO-BREAK SPACE),用FEFF表示。這正好是兩個字節,而且FF比FE大1。如果一個文本文件的頭兩個字節是FE FF,就表示該文件采用大頭方式;如果頭兩個字節是FF FE,就表示該文件采用小頭方式。

但是為什么要分大頭和小頭呢?

UTF-8編碼單位為字節,並且多節字的編碼也規定了他們的順序(低字節和高字節),因此在儲存和傳輸過程不會出現問題;

但UTF-16就不同,它以16位整數、雙字節作為編碼單位,規定了多個(兩個)雙字節編碼的順序(高位雙字節和低位雙字節),但對於每個雙字節在儲存和傳輸中,這兩個字節誰先誰后的問題。如果不作相關規定,在小頭機器中,把會雙字節中的低字節儲存(或傳輸)在前面,高字節在后;大頭機器則相反,會造成混亂和錯誤。

其實這個我也不明白,但是跟機器底層相關的就不想研究啦~如果大學學得好的應該能懂噠~可惜我忘了,只有個模糊的概念。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM