程式設計基礎-----之Unicode,UTF,ASC||的概念
關鍵字 談談Unicode編碼,簡要解釋UCS、UTF、BMP、BOM等名詞 這是一篇程式設計師寫給程式設計師的趣味讀物。所謂趣味是指可以比較輕鬆地瞭解一些原來不清楚的概念,增進知識,類似於打RPG遊戲的升級。整理這篇文章的動機是兩個問題:問題一: 使用Windows記事本的“另存為”,可以在GBK、Unicode、Unicode big endian和UTF-8這幾種編碼方式間相互轉換。同樣是txt檔案,Windows是怎樣識別編碼方式的呢? 我很早前就發現Unicode、Unicode big endian和UTF-8編碼的txt檔案的開頭會多出幾個位元組,分別是FF、FE(Unicode),FE、FF(Unicode big endian),EF、BB、BF(UTF-8)
UTF(UCS Transformation Format)規範規定怎樣傳輸這些編碼,常見的UTF規範包括UTF-8、UTF-7、UTF-16。
Unicode字元的碼位,需要1個或者2個16位長的碼元來表示,因此這是一個變長表示,所以可以相容ASC||編碼UTF-16比起UTF-8,好處在於大部分字元都以固定長度的位元組 (2位元組) 儲存,但UTF-16卻無法兼容於ASCII編碼。這是由於UTF3、UCS-2、UCS-4、BMP UCS有兩種格式:UCS-2和UCS-4。顧名思義,UCS-2就是用兩個位元組編碼,UCS-4就是用4個位元組(實際上只用了31位,最高位必須為0)編碼。下面讓我們做一些簡單的數學遊戲: UCS-2有2^16=65536個碼位,UCS-4有2^31=2147483648個碼位。 UCS-4根據最高位為0的最高位元組分成2^7=128個group。每個group再根據次高位元組分為256個plane。每個plane根據第3個位元組分為256行 (rows),每行包含256個cells。當然同一行的cells只是最後一個位元組不同,其餘都相同。 group 0的plane 0被稱作Basic Multilingual Plane, 即BMP。或者說UCS-4中,高兩個位元組為0的碼位被稱作BMP。 將UCS-4的BMP去掉前面的兩個零位元組就得到了UCS-2。在UCS-2的兩個位元組前加上兩個零位元組,就得到了UCS-4的BMP。而目前的UCS-4規範中還沒有任何字元被分配在BMP之外。4、UTF編碼
UTF-8
UTF-8以位元組為單位對Unicode進行編碼。從Unicode到UTF-8的編碼方式如下:
Unicode編碼(十六進位制) |
UTF-8 位元組流(二進位制) |
000000-00007F |
0xxxxxxx |
000080-0007FF |
110xxxxx 10xxxxxx |
000800-00FFFF |
1110xxxx 10xxxxxx 10xxxxxx |
010000-10FFFF | 11110xxx10xxxxxx10xxxxxx10xxxxxx |
UTF-8的特點是對不同範圍的字元使用不同長度的編碼。對於0x00-0x7F之間的字元,UTF-8編碼與ASCII編碼完全相同。UTF-8編碼的最大長度是4個位元組。從上表可以看出,4位元組模板有21個x,即可以容納21位二進位制數字。Unicode的最大碼位0x10FFFF也只有21位。
例如“漢”字的Unicode編碼是6C49。6C49在0800-FFFF之間,所以肯定要用3位元組模板了:1110xxxx 10xxxxxx 10xxxxxx。將6C49寫成二進位制是:0110 110001 001001, 用這個位元流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。
UTF-16
UTF-16由一個或兩個16位為單元,對Unicode字符集進行轉換的。 UTF-16以16位為單元對UCS進行編碼。對於小於0x10000的UCS碼,UTF-16編碼就等於UCS碼對應的16位無符號整數。對於不小於0x10000的UCS碼,定義了一個演算法。不過由於實際使用的UCS2,或者UCS4的BMP必然小於0x10000,所以就目前而言,可以認為UTF-16和UCS-2基本相同。但UCS-2只是一個編碼方案,UTF-16卻要用於實際的傳輸,所以就不得不考慮位元組序的問題。5、UTF的位元組序和BOM UTF-8以位元組為編碼單元,沒有位元組序的問題。UTF-16以兩個位元組為編碼單元,在解釋一個UTF-16文字前,首先要弄清楚每個編碼單元的位元組序。例如收到一個“奎”的Unicode編碼是594E,“乙”的Unicode編碼是4E59。如果我們收到UTF-16位元組流“594E”,那麼這是“奎”還是“乙”? Unicode規範中推薦的標記位元組順序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一個有點小聰明的想法: 在UCS編碼中有一個叫做"ZERO WIDTH NO-BREAK SPACE"的字元,它的編碼是FEFF。而FFFE在UCS中是不存在的字元,所以不應該出現在實際傳輸中。UCS規範建議我們在傳輸位元組流前,先傳輸字元"ZERO WIDTH NO-BREAK SPACE"。 這樣如果接收者收到FEFF,就表明這個位元組流是Big-Endian的;如果收到FFFE,就表明這個位元組流是Little-Endian的。因此字元"ZERO WIDTH NO-BREAK SPACE"又被稱作BOM。UTF-8不需要BOM來表明位元組順序,但可以用BOM來表明編碼方式。字元"ZERO WIDTH NO-BREAK SPACE"的UTF-8編碼是EF BB BF(讀者可以用我們前面介紹的編碼方法驗證一下)。所以如果接收者收到以EF BB BF開頭的位元組流,就知道這是UTF-8編碼了。 Windows就是使用BOM來標記文字檔案的編碼方式的。