对于Windows,GB18030是不可用的
生活随笔
收集整理的這篇文章主要介紹了
对于Windows,GB18030是不可用的
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
GB18030,想說愛你不容易
之所以會有此感嘆,并非覺得GB18030的編碼框架有什么不妥,而是對該標準在實際應用中遇到的尷尬情形的一些個人看法。
疑惑一:GB18030到底是一種ANSI編碼還是Unicode編碼?這本來是毫無疑問的,作為對GB2312和GBK的擴展,GB18030勢必要向下兼容這兩個編碼標準,而GB2312和GBK都是不折不扣的ANSI編碼,那么建立在這兩個標準基礎之上的GB18020也理所當然的應該是一種多字節(jié)的ANSI編碼了。
既然是ANSI編碼,那么在實際的系統(tǒng)中,它就應該是作為一種本地化的編碼字符集出現(xiàn)的。比如在Windows里面,它就應該像GBK、Big5這些ANSI編碼那樣,有自己的代碼頁和相應的代碼頁屬性(主要指引導字節(jié)和尾隨字節(jié)的取值范圍)。對于代碼頁,微軟已經給出了答案:Win2k以上的操作系統(tǒng)只要安裝了微軟的GB18030-2000擴展支持包,就可以支持GB18020-2000編碼標準的54936代碼頁了。我在安裝了18030支持包之后,根據(jù)微軟給出的測試建議,寫了個調用API函數(shù)IsValidCodePage(54936)的小程序,測試結果是54936代碼頁可用(未安裝18030支持包以前,測試54936代碼頁不可用)。
但僅僅是某個代碼頁可用并不表示文本處理程序就可以處理基于該代碼頁編碼的文本了,還必須把這個代碼頁設為系統(tǒng)的當前代碼頁才行。可是,18030擴展包不是自帶了一個GB18030?Unicode的文本編碼轉換程序的嘛,這個程序并不需要把系統(tǒng)的當前代碼頁設為54936就可以工作呀。其實,關于這一點花點時間想一下也很簡單:文本文件的內碼轉換其實根本不需要操作系統(tǒng)的支持,這種轉碼工作在計算機文本處理任務中來說算是最簡單的了――說得極端一點,只要有轉碼表,我們甚至可以寫一個在DOS下運行的GB18030?Unicode轉碼程序,如果省去中文界面的話,這個程序連中文系統(tǒng)都不用加載。在現(xiàn)實應用中,文本處理工作遠不只轉碼這一項,就拿日常用得比較多的文本編輯來說吧――假設有一款以ANSI方式來處理文本的字處理軟件,如果想要在這個軟件中正確顯示和編輯GB18030編碼的文本的話,首先就應該把系統(tǒng)的當前代碼頁設為54936才行。這是因為代表GBK的936代碼頁的屬性和代表GB18030的54936代碼頁的屬性有很大的不同,在936代碼頁下,ANSI程序是無法正確處理GB18030編碼的文本的。
那么把系統(tǒng)的當前代碼頁設為54936不就好了嗎?可是事情好像并沒有那么簡單……在編程時,通過調用API函數(shù)GetACP可以獲得系統(tǒng)當前的代碼頁,可是Win32?API里面并沒有對應提供一個類似"SetACP"這樣的設置當前代碼頁的函數(shù)。事實上即使是Windows自己,也沒有辦法直接改變系統(tǒng)當前的代碼頁, 改變當前代碼頁的方法是在控制面板中設置區(qū)域和語言選項,然后重啟才能生效。Windows區(qū)域和語言選項里面的"非Unicode程序語言版本"設置對 于普通電腦用戶來說就是為那些只能處理特定語言的程序(ANSI文本處理程序)指定一個正確的,默認可以處理的語言種類(比如是中文、日文或韓文);而對 于開發(fā)ANSI文本處理程序的程序員來說,其實就是設置系統(tǒng)當前的代碼頁。比如要設置950代碼頁的時候,選"中文(臺灣)",要設置936代碼頁的時候,就選"中文(中國)"。可是讓人難以理解的是,在安裝了18030支持包以后,"代碼頁轉換表"里面已經顯示"54936(GB18030?簡體中文)"代碼頁是可用使用的了。但在"非Unicode程序語言版本"列表里面,卻沒有相應地提供一個類似"中文(中國GB18030)"這樣的選項,也就是說:Windows根本就沒有提供給我們把代表GB18030編碼標準的54936代碼頁設為系統(tǒng)當前代碼頁的選擇。難道微軟并不認為GB18030是一種ANSI編碼,不需要相應的代碼頁支持?可是這個結論顯然跟微軟提供了54936這個代碼頁是相矛盾的,因為代碼頁本身就是處理不同本地化語言的一種機制,生來就是為ANSI編碼而設的。而且18030支持包里面的ReadMe文檔也透露了它附帶的轉碼程序其實是調用了API函數(shù)MultiByteToWideChar和WideCharToMultiByte來實現(xiàn)的(否則無法解釋這個程序怎么會只有區(qū)區(qū)25KB之小),這就是說微軟確實是把GB18030當作一種多字節(jié)的ANSI編碼來看待的。可是現(xiàn)在這個編碼的代碼頁卻根本不能設置為系統(tǒng)的當前代碼頁!這恐怕在Windows所支持的所有代碼頁里面,是唯一的一個吧。
疑惑二:54936代碼頁的真相?既然CP54936在所有的代碼頁中顯得如此之特殊,這不得不讓人產生了一窺其具體技術細節(jié)的欲望。我們知道:對于代碼頁機制來說,不同代碼頁間的主要區(qū)別在于各個位置上的字節(jié)取值范圍的不同。比如CP936的引導字節(jié)范圍在0x81-0xFE之間,尾隨字節(jié)范圍在0x40-0x7E或0x80-0xFE之間;CP932的引導字節(jié)范圍在0x81-0x9F或0xE0-0xFC之間,尾隨字節(jié)范圍在0x40-0xFC(0x7F除外)之間。顯然CP936和CP932有 很大的不同,這種不同成了系統(tǒng)在當前代碼頁下,區(qū)分哪些是有效編碼(字符)和無效編碼(字符)的依據(jù)。言歸正傳,雖然Windows需要重啟才能改變當前 代碼頁,但要查看某個代碼頁的信息卻不用那么麻煩。在任意一個代碼頁下,隨時都可以用API函數(shù)GetCPInfo讀出包括當前代碼頁在內的所有系統(tǒng)支持 的代碼頁的屬性信息。我們先用最熟悉的CP936試看看,測試結果GetCPInfo返回的信息如下:MaxCharSize=2;LeadByte={81,FE,00,00,00,00,00,00,00,00,00,00}。這個結果的意思是說:CP936的字符最大編碼長度是兩個字節(jié),它的引導字節(jié)有一個取值范圍:0x81-0xFE。顯然GetCPInfo(936)返回的信息跟我們所了解的GBK編碼標準的技術框架是符合的。接下來看看我們所關心的CP54936的情況,測試結果GetCPInfo返回的信息如下:MaxCharSize=4;LeadByte={00,00,00,00,00,00,00,00,00,00,00,00}。按照Windows代碼頁機制的說法,這個結果意味著CP54936沒有引導字節(jié)取值范圍的定義,而這種情況通常只有單字節(jié)ANSI編碼才會出現(xiàn)。難怪Windows沒有提供把54936設為系統(tǒng)當前代碼頁的選項了,因為即使把CP54936設為當前代碼頁,那些ANSI字處理程序(也就是非Unicode程序)也是無法顯示和編輯GB18030編碼的文本的。這一點可以很容易地從Windows的代碼頁技術原理上分析得到:CP54936沒有定義引導字節(jié)的取值范圍,但它本身又是一種ANSI編碼的代碼頁,所以當系統(tǒng)運行在這個代碼頁下的時候,實際上等于是運行在單字節(jié)ANSI編碼的代碼頁下面。這樣一來,當我們試圖在ANSI程序里面顯示一個四字節(jié)編碼的GB18030字符的時候,系統(tǒng)會毫不客氣地把它識別為無效編碼(字符),實際顯示出來的就是一堆的問號了。這是因為單字節(jié)ANSI編碼的每個字節(jié)取值都不會超過0x7F的,而GB18030的四字節(jié)編碼的第一、三個字節(jié)的取值都在0x81以上,根據(jù)Windows代碼頁的技術規(guī)則,當然會被判定為無效編碼(字符)了。
注:Windows的代碼頁技術原理并不難理解。系統(tǒng)里面對應不同的代碼頁存儲了不同的代碼頁屬性――包括這個代碼頁所代表的編碼標準的最大字符存儲長 度(單位:字節(jié));引導字節(jié)取值范圍;尾隨字節(jié)取值范圍(這個是隱藏的,用GetCPInfo函數(shù)是得不到它的,但它確實存在,看來微軟還是習慣性地留了 一手)。系統(tǒng)存儲這些代碼頁屬性最主要的目的就是用來判斷某個給定的字符串里面是否包含有不符合當前代碼頁編碼框架的字符(編碼),當然這種判定是對于那 些準備要送去給程序中需要顯示在用戶界面上的字符串(文本)而言的。對于發(fā)生在計算機內部(內存)里面的文本處理過程(比如文本文件的內碼轉換),是不需 要進行這種判斷的。這也就是為什么說文本文件的轉碼不需要特定系統(tǒng)的支持的原因。系統(tǒng)判斷有效編碼(字符)和無效編碼(字符)的過程是這樣的:順序讀取字 符串中每個字節(jié)值,如果出現(xiàn)一個取值不在當前代碼頁屬性許可的取值范圍(比如在單字節(jié)代碼頁中出現(xiàn)大于0x7F的字節(jié))內的字節(jié)的話,那么這個字節(jié)所屬的字符就是無效字符,在軟件界面上就會被顯示為問號。對于雙字節(jié)編碼的代碼頁(Windows支持的代碼頁都是單字節(jié)或雙字節(jié)代碼頁,只有CP54936是四字節(jié)這個例外),如果讀出的某個字節(jié)值小于等于0x7F,就說明它是一個單字節(jié)字符;如果讀出的字節(jié)值大于0x7F, 就把它當成引導字節(jié)處理,看看這個字節(jié)值是否在當前代碼頁指定的引導字節(jié)取值范圍內,以及它的下一個字節(jié)值是否在當前代碼頁指定的尾隨字節(jié)取值范圍內。如 果這兩個條件都成立,說明當前讀到的這個字節(jié)和它的下一個字節(jié)組成了一個有效的雙字節(jié)字符,否則當前字節(jié)值判為無效編碼,顯示為問號。
上述這個判定過程是真實存在的,完整的編碼有效性判定工作需要引導字節(jié)取值范圍和尾隨字節(jié)取值范圍兩個基本信息的支持。只是不知道微軟出于什么原因,只 開放了引導字節(jié)取值范圍,但從Windows在文本處理上的一些行為中,是可以發(fā)現(xiàn)尾隨字節(jié)取值范圍信息是肯定存在的。比如,在簡體中文系統(tǒng)下(CP936)寫一個ANSI的小程序:這個程序的界面包括一個Edit控件和一個Button控件(兩個控件的字體屬性已經設置成了"宋體-18030"),編寫B(tài)utton控件的鼠標單擊過程實現(xiàn)把一個編碼字節(jié)值序列為<82?34?84?34>的ANSI字符串賦值給那個Edit控件讓它顯示"?"(0x82348434是CJK ExtA漢字"?"的GB18030編碼)這個字的功能。做這個實驗程序的目的是要測試在CP936代碼頁下,ANSI程序是否能支持GB18030編碼字符的顯示和編輯。該程序的運行結果是,按下Button按鈕之后,Edit編輯框里面并沒有如希望的那樣顯示"?",而是??。顯然Windows認為在當前代碼頁(CP936)下面,0x82348434是兩個非法字符。因為這個編碼字節(jié)序列由四個字節(jié)組成,當系統(tǒng)讀出第一個字節(jié)0x82的時候,因為這個字節(jié)值大于0x7F,所以需要判斷它和下一個字節(jié)0x34能否組成一個雙字節(jié)字符,而由于0x34不在GBK尾隨字節(jié)取值范圍之內,所以第一和第二字節(jié)被判定為無效編碼;而第三字節(jié)的0x84和第四字節(jié)的0x34也是一樣的。所以這四個字節(jié)組成的編碼序列被判定為兩個無效字符,在軟件界面(Edit控件)上被顯示成了兩個問號。系統(tǒng)的這一處理結果反映了尾隨字節(jié)取值范圍信息的真實存在,否則很難想象它怎么會把0x8234判斷為無效字符。因為根據(jù)雙字節(jié)ANSI編碼框架的一般規(guī)則:組成雙字節(jié)字符的前后兩個字節(jié)中,第一個字節(jié)必須大于0x7F以便文本處理程序把這個字節(jié)和單字節(jié)字符編碼區(qū)分開來。而對第二個字節(jié)的取值范圍并不作特別的規(guī)定,可以是任意取值范圍(包括小于等于0x7F的ASCII編碼值范圍)。如果系統(tǒng)中沒有存儲GBK尾隨字節(jié)取值范圍定義的話,由于第一個字節(jié)0x82已經符合GBK引導字節(jié)取值范圍的要求了,第二個字節(jié)不管取什么值都應該判定這兩個字節(jié)組成的字符是有效的雙字節(jié)字符。而事實是Windows準確地判斷出了0x8234不符合GBK的雙字節(jié)編碼框架,這只能說明它是清楚地知道GBK的尾隨字節(jié)取值范圍定義的。
實驗分析到這里,結論已經很明顯了:在目前正式發(fā)行的Windows操作系統(tǒng),包括微軟聲稱能支持GB18030的Win2k、WinXP和Win2003中,即使安裝了GB18030-2000擴展支持包,也不能真正使這些系統(tǒng)支持GB18030編 碼標準。因為道理再簡單不過了,程序員根本就沒有辦法編寫出能在這些系統(tǒng)下顯示和編輯GB18030-2000四字節(jié)編碼文本的ANSI文本處理程序。不 是很清楚這些系統(tǒng)是怎么通過GB18030-2000的標準符合性測試的。因為這些產品并不完全符合其中的"體系正確性:產品必須能夠正確識別和處理按照 國家標準GB?18030進行編碼的文本文件。"這項要求。而微軟提供的GB18030支持包充其量只是提供了一個字體和幾個修改過的字符編碼轉換API函數(shù),以及一個無法使用的CP54936,最后用一個其實跟系統(tǒng)支不支持GB18030標準并沒有關系的內碼轉換小程序就蒙混過關了。
為什么GB18030制定出來已經6年 了,卻一直沒有得到有效的應用?為什么我們大部分的應用程序還只能停留在處理GBK字符集的階段?為什么當我們很多公民在電腦中錄入自己包含生僻字的姓名 時仍然只能用×來代替?其實這并不怪GB18030-2000的編碼技術框架不好,而是相關部門在推廣應用該標準上虎頭蛇尾的態(tài)度造成的。單以編碼框架而 言,雖然一直被很多人視為Unicode/ISO10646的中國版(實際上也是)。但技術上還是有它自己獨到之處的,即使它的四字節(jié)編碼框架跟傳統(tǒng)的單/雙字節(jié)ANSI編碼相比顯得不是那么的標準,但還不至于另類到無法處理的地步。個人認為它的四字節(jié)編碼格式跟UTF-16編碼格式的代理對機制在處理思想上很有些相似之處,從應用層來說,單獨某款軟件要識別和處理這種單、雙、四字節(jié)混合編碼并不困難。但要把這些技術融入到整個操作系統(tǒng)之中,并不是簡單地修改幾個API就能完成的,單是把Win32?API里面所有有關Ansi字符串處理的函數(shù)列出來就夠嚇人一跳的了。因為微軟不可能單為了一個GB18030放棄其他的ANSI編碼標準,加入對GB18030的 支持必須是確保兼容原有的代碼頁機制的前提下才能實施的。而要保證這一點,就必須對幾乎所有的字符串處理API進行一定的修改。總之以當年的情形,微軟是 很難在短時間之內拿出完整的解決方案的。政府壓得急,微軟草草地拿出了個換湯不換藥的支持包應付了事,沒想到還真通過了。也不知道政府是不是真的不清楚這 個支持包的底細,反正自從這場"GB18030-2000標準之爭"以微軟推出擴展支持包這個皆大歡喜的體面方式收場之后,雙方好像就沒把推廣應用這回事 放心上了。幾年中就一直任由應用層面上這種不尷不尬的局面持續(xù)下來,把一班滿心期待迎接GB18030時代卻又不明就里的中國應用開發(fā)人員撩在了一邊。這些人在經過了幾次徒勞的嘗試之后,終于還是放棄了支持GB18030標準的念頭,要么退回到GBK的小窩,要么踏上了Unicode未知的前程。總之在大家看來結論都是一樣的:對于Windows,GB18030是不可用的。
? 最近聽說新版的GB18030-2005已經于去年年底制定出來了,雖然尚未有幸一睹標準原文真容,但希望它不會步GB18030-2000的后塵。落 個不尷不尬的局面吧,因然從長遠來說主流肯定是Unicode,但短期內仍然還是ANSI和Unicode并存的局面。像GB18030這種本地化版本的Unicode還是需要的。希望它的應用價值不要被再度埋沒了。雖然這不是我這種小人物的努力就可以決定的。
總結
以上是生活随笔為你收集整理的对于Windows,GB18030是不可用的的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: e派android 4.4.4,实用GP
- 下一篇: (已更新)新独立系统社群空间站最新源码开