7.Unicode、UCS
以上的編碼都是本地化編碼, 一國之內還沒有問題,但是要跨國,就不行了 。比如漢字,在只有ISO-8859系列字符集的電腦上顯示就只能是亂碼了,要顯示漢字,電腦上必須裝GB2312或GBK的字符集。有沒有一個字符集,能夠包含全球所有的字符呢?這就是Unicode和UCS
1988年,Joe Becker 發布了一個草案,提出了“Unicode”的概念,他解釋說“‘Unicode’是一種唯一的、統一的、全球的編碼”。后來,RLG、Sun、Microsoft、NeXT(喬布斯被趕出蘋果后創建的公司)的人也都逐漸加入到Unicode工作組里。1991年1月3日,Unicode聯盟組織成立,同年發布了Unicode1.0.
同時,ISO組織也在做同樣的事情,創造一個全球統一的字符集(Universal Coded Character Set,簡稱UCS),1993年發布了標準ISO 10646-1。
后來,兩個組織認識到,世界不需要兩個不兼容的字符集,于是,開始合作。從Unicode2.0開始,開始采用和UCS相同的字庫和字碼。這樣,兩個項目仍都存在,并獨立地公布各自的標準。但雙方都同意保持兩者標準的碼表兼容,并緊密地共同調整任何未來的擴展。所以,現在說到UCS字符集,跟Unicode可以看成一回事。
Unicode編碼包含兩個層次:第一層定義字符的數值和第二層 定義數值的實現方式 。Unicode用數字 0x0~0x10FFFF 表示所有字符,所以最多可以容納 1114112 個字符。 數值的編碼方式,也就是實現方式包括 UTF-8,UTF-16,UTF-32 三種 。
有人會說,Unicode不是兩個字節表示字符的碼?為什么數值可以到0x10FFFF,這不21位,兩個半字節還多了嗎?其實,這是混淆了Unicode的數值定義和實現,這根本就是兩個概念,Unicode到底用幾個字節表示,取決于其實現方式是UTF-8,UTF-16,還是UTF-32.
比如,“漢字”對應的Unicode值是0x6c49和0x5b57,而編碼實現是:
char data_utf8[]= {0xE6,0xB1,0x89,0xE5,0xAD,0x97}; //UTF-8編碼 char16_t data_utf16[]= {0x6C49,0x5B57}; //UTF-16編碼 char32_t data_utf32[]= {0x00006C49,0x00005B57}; //UTF-32編碼
UTF-8
UTF,全稱“Unicode Transformation Formats”。是Unicode的編碼格式。
UTF-8是使用8-bit為單位,對Unicode進行編碼的。特點是,對不同范圍的字符使用不同長度的編碼。
Unicode編碼(十六進制) | UTF-8 字節流(二進制) |
---|---|
00000000 - 0000007F | 0xxxxxxx |
00000080 - 000007FF | 110xxxxx 10xxxxxx |
00000800 - 0000FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
00010000 - 001FFFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
00200000 - 03FFFFFF | 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx |
04000000 - 7FFFFFFF | 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx |
UTF-8 的編碼規則很簡單: 如果只有一個字節,那么最高的比特位為 0;如果有多個字節,那么第一個字節從最高位開始,連續有幾個比特位的值為 1,就使用幾個字節編碼,剩下的字節均以 10 開頭 。具體的表現形式為(xxx 就用來存儲 Unicode 中的字符編號):
0xxxxxxx:單字節編碼形式,這和 ASCII 編碼完全一樣,因此 UTF-8 是兼容 ASCII 的;
110xxxxx 10xxxxxx:雙字節編碼形式;
1110xxxx 10xxxxxx 10xxxxxx:三字節編碼形式;
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx:四字節編碼形式。
下面是一些字符的編碼實例(綠色部分表示本來的 Unicode 編號):
字符 | N | ? | 齊 |
---|---|---|---|
Unicode 編號(二進制) | 01001110 | 11100110 | 00101110 11101100 |
Unicode 編號(十六進制) | 4E | E6 | 2E EC |
UTF-8 編碼(二進制) | 01001110 | 11000011 10100110 | 11100010 10111011 10101100 |
UTF-8 編碼(十六進制) | 4E | C3 A6 | E2 BB AC |
UTF-8編碼的最大長度是6個字節。
- 對于0x00-0x7F之間的字符,UTF-8編碼與ASCII編碼完全相同,用1個字節表示,首位為0。
- 對于0x80-0x7FF之間的字符,用2個字節表示,第一個字節前三位“110”為標志位,第二個字節前兩位“10”為標志位。剩下的11位用來表示Unicode值(7FF最多11位)。
- 同樣,UTF-8的3個字節,可以表示0x800-0xFFFF的Unicode(最多16位)。
- UTF-8的4個字節,可以表示0x10000-0x001FFFFF的Unicode(最多21位)。 4個字節以內,已經包含了Unicode所有字符。
- 5、6個字節表示的已經是非Unicode編碼范圍,屬于UCS-4 編碼。早期UTF-8規范也可以達到6字節序列,不過2003年11月UTF-8 被 RFC 3629 重新規范,只能使用原來Unicode定義的區域, U+0000到U+10FFFF。根據規范,這些字節值將無法出現在合法 UTF-8序列中。
例1:“漢”字的Unicode編碼是0x6C49。0x6C49在0x0800-0xFFFF之間,使用用3字節模板了:1110xxxx 10xxxxxx 10xxxxxx。將0x6C49寫成二進制是:0110 1100 0100 1001, 用這個比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。
例2:Unicode編碼0x20C30在0x010000-0x10FFFF之間,使用用4字節模板了:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx。將0x20C30寫成21位二進制數字(不足21位就在前面補0):0 0010 0000 1100 0011 0000,用這個比特流依次代替模板中的x,得到:11110000 10100000 10110000 10110000,即F0 A0 B0 B0。
UTF-8有兩個好處:
-
- 1字節字符、2字節字符、3字節字符……的首字節標志位不同,這樣可以很清楚的區分一個字節屬于1字節字符還是2字節字符,如果一個字節流傳輸中出現錯誤,也不會錯位,只影響部分字符,根據標志位,很容易找到下個正確字符。
-
- 兼容ASCII碼, 英美字符用UTF-8可以一個字節表示,所以,www組織選用UTF-8作為推薦編碼格式。2007年,在互聯網上,UTF-8格式已經超過了ASCII碼。
UTF-16
UTF-16以2字節為單位,等同于UCS-2.
Unicode編碼(十六進制) | UTF-16 字節流(二進制) |
---|---|
00000000 - 0000FFFF | xxxxxxxx xxxxxxxx |
00010000 - 0010FFFF | 110110yyyyyyyyyy 110111xxxxxxxxxx |
Unicode值小于等于0xFFFF的,直接用兩個字節表示,超過0xFFFF的,無法用兩個字節表示。使用下面公式編碼:
-
1.計算 U’= U – 0x10000 2. 將U'寫成二進制形式:yyyy yyyy yyxx xxxx xxxx 3. 加上標志位,1101 10yy yyyy yyyy 1101 11xx xxxx xxxx:高位代理值為D800,低位代理值為DC00
可見,這是4個字節表示,2個6位標志位,20位有效位。因為U最大是0x10FFFF,所以U’最大是0xFFFFF,20位足夠表示 。
案例1:
U+0020,這個值的范圍在第一部分,即經過UTF-16編碼后,結果仍然為U+0020,在內存中的順序為00 20。
案例2:
U+12345, 這個值的范圍在第二部分,因此需要先減去0x10000,得到0x02345,拆分成高10位00 0000 1000和低10位11 0100 0101。根據上面規則加上特定值后,高位代理值為D808,低位代理值為DF45,最終內存中的順序為D8 08 DF 45。
BOM的含義
BOM即Byte Order Mark字節序標記。BOM是為UTF-16和UTF-32準備的,用戶標記字節序(byte order)。拿UTF-16來舉例,其是以兩個字節為編碼單元,在解釋一個UTF-16文本前,首先要弄清楚每個編碼單元的字節序。例如收到一個“奎”的Unicode編碼是594E,“乙”的Unicode編碼是4E59。如果我們收到UTF-16字節流"594E",那么這是“奎”還是“乙”?
我們先來來看下UTF-16-Big Endian文件格式:
可以看到此時“文件”二字的unicode編碼并沒有超過0xFFFF,所以使用兩個字節來保存:
而 最早的“fe ff”即為Bom標簽 。
我們再來看下UTF-16-Little Endian文件格式:
使用的Bom標簽居然變為了fffe。
Unicode規范中推薦的標記字節順序的方法是BOM:在UCS編碼中有一個叫做"ZERO WIDTH NO-BREAK SPACE"(零寬度無間斷空間)的字符,它的編碼是FEFF。而FEFF在UCS中是不不能再的字符(即不可見),所以不應該出現在實際傳輸中。UCS規范建議我們在傳輸字節流前,先傳輸字符"ZERO WIDTH NO-BREAK SPACE"。這樣如果接收者接收到FEFF,就表明這個字節流是Big-Endian的;如果收到FFFE,就表明這個字節流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被稱為BOM。
windows上默認的Unicode編碼方式就是UTF-16,使用wchar_t表示。
UTF-32
UTF-32編碼以4字節為單位 。直接把Unicode值轉為4字節二進制數就是其UTF-32編碼。等同于UCS-4.
8.Base64
有的電子郵件系統(比如國外信箱)不支持非英文字母(比如漢字)傳輸,這是歷史原因造成的(認為只有美國會使用電子郵件?)。因為一個英文字母使用ASCII編碼來存儲,占存儲器的1個字節(8位),實際上只用了7位2進制來存儲,第一位并沒有使用,設置為0,所以,這樣的系統認為凡是第一位是1的字節都是錯誤的。而有的編碼方案(比如GB2312)不但使用多個字節編碼一個字符,并且第一位經常是1,于是郵件系統就把1換成0,這樣收到郵件的人就會發現郵件亂碼。
為了能讓郵件系統正常的收發信件,就需要把由其他編碼存儲的符號轉換成ASCII碼來傳輸。比如 , 在一端發送GB2312編碼->根據Base64規則->轉換成ASCII碼,接收端收到ASCII碼->根據Base64規則->還原到GB2312編碼 。
9.Big5
在臺灣、香港與澳門地區,使用的是繁體中文字符集。而1980年發布的GB2312面向簡體中文字符集,并不支持繁體漢字。在這些使用繁體中文字符集的地區,一度出現過很多不同廠商提出的字符集編碼,這些編碼彼此互不兼容,造成了信息交流的困難。為統一繁體字符集編碼,1984年,臺灣五大廠商宏碁、神通、佳佳、零壹以及大眾一同制定了一種繁體中文編碼方案,因其來源被稱為五大碼,英文寫作Big5,后來按英文翻譯回漢字后,普遍被稱為大五碼。 大五碼是一種繁體中文漢字字符集,其中繁體漢字13053個,808個標點符號、希臘字母及特殊符號。大五碼的編碼碼表直接針對存儲而設計,每個字符統一使用兩個字節存儲表示。第1字節范圍81H-FEH,避開了同ASCII碼的沖突,第2字節范圍是40H-7EH和A1H-FEH。因為Big5的字符編碼范圍同GB2312字符的存儲碼范圍存在沖突,所以在同一正文不能對兩種字符集的字符同時支持。 Big5編碼的分布如表1-5所示,Big5字符主要部分集中在三個段內:標點符號、希臘字母及特殊符號;常用漢字;非常用漢字。其余部分保留給其他廠商支持。
Big5編碼推出后,得到了繁體中文軟件廠商的廣泛支持,在使用繁體漢字的地區迅速普及使用。目前,Big5編碼在臺灣、香港、澳門及其他海外華人中普遍使用,成為了繁體中文編碼的事實標準。在互聯網中檢索繁體中文網站,所打開的網頁中,大多都是通過Big5編碼產生的文檔。
總結各種字符編碼之間的關系
上面關于字符集和編碼講了許多概念,其實歸類一下可以這么理解: 首先是單字節字符集:
- 1、最初美國ANSI發明了自己的編碼ASCII,7-bit足夠,這是標準ASCII。
- 2、標準ASCII碼沒有西歐國家拉丁文、英鎊等字符,各公司、國家開始擴展,形成自己的擴展ASCII碼字符集,各方混戰,不過8-bit也就足夠。
- 3、天下分久必合,ISO統一了8-bit字符集,叫做ISO 8859.
但是亞洲國家字符更多,一個字節遠遠不夠,于是用多個字節表示,擴展形成本國字符集,中國GB系列,臺灣Big5,日本JIS……,這些叫做多字節字符集(MBCS),windows中用雙字節表示,也叫做(DBCS)。
以上字符都是群雄割據,各自為政,windows為了迎合大家需求,在哪個國家,默認編碼就用那個國家的,不過后來不知怎么被誤傳位ANSI編碼,其實ANSI怎么可能定義世界各國編碼,不過可以理解成各編碼都是在ANSI*礎上擴展的,因為都兼容ANSI的標準ASCII碼。
這時,ISO再次出手,和Unicode聯盟攜手打造了Unicode(UCS),意圖一統江湖。Unicode確實包羅萬象,涵蓋了各國字符,于是流行世界。Unicode自身只定義了每個字符的數值,真正二進制編碼格式卻是UTF-8,UTF-16(UCS-2),UTF-32(UCS-4)。
我們下期見。
參考
刨根究底字符編碼之五——簡體漢字編碼方案(GB2312、GBK等)以及全角、半角、CJK
字符集和字符編碼
-
計算機
+關注
關注
19文章
7537瀏覽量
88643 -
編碼
+關注
關注
6文章
957瀏覽量
54953 -
BUG
+關注
關注
0文章
155瀏覽量
15723
發布評論請先 登錄
相關推薦
評論