前面的一些篇章更多談論了Unicode的相關話題,雖然也有提到GBK等編碼,但都沒細說,這裏打算系統說一下。GB系列包括GB2312,GBK,GB18030.java
前面已經提過,GB=Guo Biao=國標=國家標準,至於所謂的2312就是一編號了,沒有其它特別的意義,18030相似。GBK沒有編號,因此它實際上並非國家標準,只是一個事實標準,GBK中K指「擴展」的意思。測試
最先的是GB2312,咱們從它開始提及。字體
如下爲一簡介(官方文檔見"國家標準化管理委員會"網站:http://gbread.sac.gov.cn/bzzyReadWebApp/standardresources.action?m=readFile&bzNum=GB%202312-1980&flag=1,用IE打開,它要安裝一個ActiveX插件):網站
GB 2312-1980,全稱《信息交換用漢字編碼字符集 基本集》,由國家標準總局於1980年3月9號發佈,1981年5月1日實施,通行於大陸。新加坡等地也使用此編碼。它是一個簡化字的編碼規範,也包括其餘的符號、字母、日文假名等,共7445個圖形字符,其中漢字佔6763個。編碼
上述官網地址沒法下載,若是你想下載,可試下這個ftp://ftp.oreilly.com/examples/cjkvinfo/AppE/gb2312.pdf(比標準方案多增長了一些字符)spa
做爲一個編碼字符集而言,前面也曾說到,它採用了所謂的二維區位編號,下面是一個概覽圖:操作系統
它是一個94×94的表格,理論上有94×94=8836個空間。.net
橫的叫區,豎的叫位,總共94個區,區和位的編號都從1開始。能夠看到粗略有三大部分。插件
1. 中間黑色的主體部分便是漢字區了,具體爲16-87區,共87-16+1=72個區,理論空間爲72×94=6768.設計
從上圖中能夠看到中間有5個編碼爲空白(中間靠右邊部分,55區最後5個位),因此總共有6768-5=6763個漢字。
一級漢字與二級漢字:
第16-55區:一級漢字,3755個(以拼音字母排序)
第56-87區:二級漢字,3008個(以部首筆畫排序)
2. 最下面的88-94區是有待進一步標準化的空白區。
3. 關於前面的01-15區,下圖爲概覽圖左上角的局部放大圖:
1. 01-09區爲符號、字母、日文假名等,部分區還有空白位。
03區便是對應ASCII字符的全角字符區。輸入法的全角模式下輸入的便是這些字符。
2. 10-15區也是有待進一步標準化的空白區。
各區的一個具體狀況:
第01區:中文標點、數學符號以及一些特殊字符
第02區:序號
第03區:全角西文字符
第04區:日文平假名
第05區:日文片假名
第06區:希臘字母表
第07區:俄文字母表
第08區:中文拼音字母表
第09區:製表符號
第10-15區:未定義
第16-55區:一級漢字(以拼音字母排序)
第56-87區:二級漢字(以部首筆畫排序)
第88-94區:未定義
在上圖中還標出了一個漢字「啊」,它就是GB2312方案中的天字第一號漢字,它處於16區01位上,因此它的區位碼便是1601.
所謂區位碼就是這一94×94的大表格中的行號與列號了,均從1開始編號。
第一個字符0101爲「全角空格」(圖中顯示爲SP(space))。
將區位碼的區和位分別加上32(=0x20)就獲得了國標碼。
「啊」的區位碼是16-01,分別加32,獲得16+32-01+32=48-33,便是國標碼。固然,你一般應該寫成16進制,48-33便是0x30-0x21,因此3021便是「啊」十六進制的國標碼,使用兩字節保存,30爲高字節,21爲低字節。以下:
GB2312方案規定,對上述表中任意一個圖形字符都採用兩個字節表示,每一個字節均採用七位編碼表示。
如上圖所示,只用了7位,這便是說最高位就是0了。
但爲什麼不直接採用區位碼呢?爲何要加32呢?你也許還記得前面說到ASCII時,前面32個字符是控制碼,中文系統天然也不能少了這些控制碼,爲了避免與這些控制碼衝突,加上32就能跳過它們了。
一字節有128個空間,128-32=96,實際上,ASCII中第127個也是控制碼(DEL, 刪除),再減去就還有95個有效位,再加上區位從1開始,又損失了一位,因此最終只有94個有效位了,這也是前面爲什麼是一個94×94的表格。
國標碼的定位實際應該是與ASCII一致的,是做爲國家信息交換的標準碼。從設計上看,它並沒打算兼容ASCII,它已經把ASCII中的字符收錄了過來,不過是做爲所謂的全角字符來看待,但全角英文顯示效果實際上是不好的,下面是全角英文的一個示例:
hello,world
顯得很是不緊湊,最終,一種能兼容ASCII的存儲方案獲得了普遍採納,這就是所謂的機內碼了。
將國標碼高低字節分別加上0x80(=128)就獲得了機內碼(有時又叫交換碼)。128的二進制形式爲10000000,加128,簡單地講,就是把國標碼最高位置成1.至於爲何要這樣呢?我想你應該也清楚了,就是要兼容ASCII,ASCII最高位爲0,國標碼加128後,高低字節的最高位都成了1,這樣就與ASCII區分開來。
將「啊」的國標碼3021分別加上0x80,0x30+0x80=0xB0,0x21+0x80=0xA1,因此B0A1便是機內碼。
若是從區位碼算起,那麼則是加上0x20+0x80=32+128=160=0xA0,也即區位碼的區和位分別直接加上0xA0便可獲得機內碼,以下圖所示:
若是你新建一個文本文件,錄入「啊」字,以GB2312編碼方式保存(使用GBK便可,它兼容GB2312),再用十六進制查看,你會發現使用的是機內碼:
使用代碼的測試也可驗證這一點:
@Test public void testAh() throws UnsupportedEncodingException { String ah = "啊"; assertThat(DatatypeConverter.printHexBinary(ah.getBytes("GB2312"))).isEqualTo("B0A1"); }
雖然咱們常把GB2312稱爲國標碼,但咱們應該清楚,實際存儲使用的是機內碼,一般說到GB2312編碼時指的就是這個機內碼了。它能兼容ASCII,是一種變長的編碼方案,對ASCII中的字符(也即所謂的「半角西文字符」)採用一字節編碼,最高位爲0;對區位表中的字符采用兩字節編碼,且每字節最高位均爲1,以此區分。
天然,全角英文字符就是兩字節編碼了,跟漢字是同樣的。
下面是一個混合了漢字,半角字母a和全角字母a的編碼示例,共5個字節:
咱們說GB2312是一個變長編碼方案,是站在其兼容ASCII編碼角度而言,就其方案標準自己定義的字符而言,它是一個雙字節定長編碼方案。
你可能會想,那國標碼還有什麼用?
我我的以爲,國標碼既然稱爲中文信息交換的標準碼,必然要成爲「機內」碼纔有意義,只不過因爲各類緣由,最終未能如願。早期的一些系統或者一些小型的嵌入式系統或許採納了它作爲「機內」碼。固然以上爲我的猜想,僅供參考。
另:我在前面的一些文章中談到區位碼時把它與機內碼混爲一談,特此更正。
下面是三種碼在256×256座標中的位置的一個示意圖:
GBK是對GB2312的一個擴展,兼容GB2312,所以也兼容ASCII,也是一個變長編碼方案。下面是一個簡介:
GBK整體編碼範圍爲8140-FEFE,首字節在81-FE 之間,尾字節在40-FE 之間,總計23940 個碼位,共收入21886個漢字和圖形符號,其中漢字(包括部首和構件)21003 個,圖形符號883 個。
GBK是國家有關部門與一些信息行業企業等一塊兒合做推出的方案,但並未做爲國家標準發佈,只是一個事實上的標準,一個過渡方案,爲GB18030標準做的一個準備。
下面是Windows Code page: 936 (GBK),第一字節的概況(來自http://msdn.microsoft.com/en-US/goglobal/cc305153.aspx)
Code page 936實質上是GBK到UTF-16編碼的一個轉換表,圖中字符下面標註的四位16進制數字便是UTF-16編碼
1. 上面部分是兼容ASCII單字節編碼。
2. 下面陰影部分是雙字節編碼中的第一個字節,表中做爲超連接,能夠點擊進去查看具體內容。
注:0x80(=128)被用於歐元符。(圖中小圓框部分)0xFF則保留,實際共有128-2=126塊。
另:新的GB18030標準使用雙字節編碼歐元符號,去掉了這個單字節編碼。
前面說到「啊」的機內碼是B0A1,咱們點擊B0(上圖中紅色小框部分)去查看一下(來自http://msdn.microsoft.com/en-US/goglobal/gg675356):
1. 「啊」位於A1處,因此它是兼容GB2312的。而前面的那些字符就是GBK擴展的了。
「啊」下面的554A便是它的UTF-16編碼。GBK與UTF-16之間編碼的轉換隻能經過查表實現。
2. 第二字節從0x40開始,不是從0x00也不是從0x80開始。表格只有12行。
由於不是從0x80開始,這意味着第二字節最高位也多是0.這點與GB2312不一樣,GB2312確保了不管是高低字節最高位均是1。
3. 另外0x7F和0xFF兩處保留未定義。
因此實際有12×16-2=192-2=190個字符。注:並不是全部的塊裏面都是190個字符,也有很多是少於190的。
粗略估算可得126×190=23940,因此GBK也就是兩萬多個字符這樣子。
GBK使用兩字節保存中文,也能兼容ASCII,而對經常使用漢字,UTF-8都是採用三字節編碼,所以不管是全中文仍是中英文混合的狀況,GBK保存的效率都要好於UTF-8.
這也不奇怪,畢竟是親生的。
但它也有些很差的地方,好比它不能支持一些國際性的文字,在國際化,通用性方面它確定不如UTF-8;就漢字而言,因爲容量空間的限制,它也沒法收錄更多的漢字了。
因此,怎麼選擇,本身看着辦。
GB18030先後發佈了兩個標準,最新的是2005年發佈的GB 18030-2005(《信息技術 中文編碼字符集》),2000年還有一版GB18030-2000,更多瞭解可參考百度百科http://baike.baidu.com/view/889058.htm,官網見http://gbread.sac.gov.cn/bzzyReadWebApp/standardresources.action?m=readFile&bzNum=GB 18030-2005&flag=1,(注:這個文件比較大)
對於多數用戶而言,無需瞭解太多,這裏也不打算詳細介紹,下面是一些簡介(針對最新的GB18030-2005):
它也是一個多字節編碼方案,有一,二,四字節三種變長組合。
它的編碼空間很大,高達160萬(約數),這甚至超過了Unicode規定的110萬(約數)。
它兼容GB2312,基本兼容GBK(只有不多幾處不一樣)。
它收錄高達7萬多的漢字,Unicode中的CJK統一漢字,CJK統一漢字擴充A,CJK統一漢字擴充B均收錄了進來。
它還支持許多少數民族如藏、蒙古、彝、維吾爾等的文字。
對於普通用戶,超大字符集不多用到,一般狀況下,如Windows系統下你可能要安裝GB18030的相關插件才能處理及顯示那些增補的字符,通常系統默認狀況也不會安裝能支持完整顯示GB18030全體字符的字體。
GB18030做爲一個強制標準,但因爲採用了高達四字節的情形,不管是操做系統仍是各類應用軟件,可能涉及許多調整才能很好地支持,這決不是一件簡單的事情。
做爲國際性標準的Unicode,BMP之外的字符的處理與顯示都還有不少不完善,因此若是GB18030沒有獲得很好的支持,那也不足爲奇了。
關於GB系列的編碼就說到這裏。