王玉++張永勝
摘 要:針對(duì)目前字符編碼方式眾多的現(xiàn)狀,應(yīng)用軟件如何更好的判斷文件編碼屬于何種字符集,并將其正確的解碼成為不容忽視的問(wèn)題。針對(duì)Windows記事本不能正常顯示“聯(lián)通”二字的Bug進(jìn)行分析,利用Winhex軟件解析文件獲得16進(jìn)制編碼,根據(jù)得到的編碼分析誤判原因,通過(guò)注釋記事本IsTextUTF8函數(shù)對(duì)分析得到的誤判原因進(jìn)行證實(shí),進(jìn)一步找到了更多Windows記事本無(wú)法正常顯示的漢字。
關(guān)鍵詞:編碼方式;字符集;UTF-8;記事本;誤判
中圖分類號(hào):TP391.1 文獻(xiàn)標(biāo)識(shí)碼:A
1 引言(Introduction)
在Windows操作系統(tǒng)環(huán)境下,新建一個(gè)記事本文檔,輸入“聯(lián)通”二字,保存并退出,再次打開(kāi)該文件時(shí),會(huì)發(fā)現(xiàn)“聯(lián)通”二字顯示為亂碼。該現(xiàn)象普遍存在于中文WIN2000、2000 Pro、2000Server、XP、WIN7、WIN8、WIN8.1等系統(tǒng)中,這是Windows記事本自身存在的一個(gè)Bug,至今仍未解決。到底是什么原因?qū)е铝嗽摤F(xiàn)象的存在呢?
這是計(jì)算機(jī)編碼方式問(wèn)題導(dǎo)致的。Windows記事本保存文件有4種編碼類型,分別為ANSI、Unicode、Unicode big endian、UTF-8,默認(rèn)保存編碼類型為ANSI。輸入“聯(lián)通”二字后,記事本通過(guò)ANSI編碼方式對(duì)其進(jìn)行存儲(chǔ),再次打開(kāi)該文件時(shí),記事本錯(cuò)誤的判斷該文件是由UTF-8進(jìn)行編碼的,便通過(guò)對(duì)應(yīng)的解碼方式進(jìn)行解碼(Decoding)。由于ANSI和UTF-8編碼方式和所屬字符集的差異,最終呈現(xiàn)出人們看到的亂碼。本文針對(duì)該問(wèn)題進(jìn)行研究。
2 各種編碼方式特點(diǎn)及其發(fā)展(Characteristics and
development of various encoding)
2.1 關(guān)于ASCII碼與擴(kuò)展字符集
ASCII碼是在1947年由美國(guó)國(guó)家標(biāo)準(zhǔn)學(xué)會(huì)(American National Standard Institute,ANSI)制定的美國(guó)標(biāo)準(zhǔn)信息交換代碼(American Standard Code for Information Interchange,ASCII),使用7個(gè)二進(jìn)制位(占一個(gè)字節(jié),首位補(bǔ)0),共128種組合表示所有大小寫(xiě)字母[1]。包括數(shù)字0到9,標(biāo)點(diǎn)符號(hào)以及在美式英語(yǔ)中使用的特殊控制符號(hào),屬單字節(jié)字符編碼系統(tǒng)。
ASCII碼無(wú)法表示一些歐洲國(guó)家的常用字符,如英鎊符號(hào)(£)。因此,1981年在標(biāo)準(zhǔn)ASCII碼的基礎(chǔ)上,使用沒(méi)有用到的最高碼位,共8個(gè)二進(jìn)制位,擴(kuò)展了128到255(0x80-0xff)共128種狀態(tài)的字符,稱為擴(kuò)展字符集。
2.2 關(guān)于GB2312、GBK、GB18030編碼
標(biāo)準(zhǔn)ASCII碼和擴(kuò)展字符集仍然不能滿足世界各地的需要,所以不同國(guó)家制定了自己特有的字符集。如中國(guó),以ASCII碼為基礎(chǔ)制定了GB2312編碼集。GB2312規(guī)定小于127的沿用ASCII碼,當(dāng)兩個(gè)大于127的字符連在一起時(shí)表示一個(gè)漢字,這樣組合出6763個(gè)簡(jiǎn)體漢字、682個(gè)符號(hào)[2]。同時(shí)將數(shù)字、標(biāo)點(diǎn)、字母都重新編排了占兩個(gè)字節(jié)的編碼,這就是半角全角的問(wèn)題。1995年又以GB2312為基礎(chǔ)擴(kuò)展制定了GBK標(biāo)準(zhǔn)。GBK沿用GB2312的標(biāo)準(zhǔn),但要求連在一起的兩個(gè)字符只要第一個(gè)大于127就表示一個(gè)漢字。為了方便少數(shù)民族,后又制定了GB18030編碼。
從ASCII、GB2312到GBK再到GB18030,都是向下兼用的,即同一個(gè)字符在這些方案中總有相同的編碼,后來(lái)的標(biāo)準(zhǔn)支持更多的字符,從ANSI派生出的字符集都稱為ANSI字符集。
2.3 關(guān)于Unicode編碼
世界各地不同語(yǔ)言都制定了自己的字符集,種類繁多,國(guó)際交流中需要轉(zhuǎn)換字符集極其不便[3]。因此,國(guó)際標(biāo)準(zhǔn)化組織(International Organization for Standardization,ISO)開(kāi)展了ISO/IEC 10646項(xiàng)目,全稱“Universal Multiple-Octet Coded Character Set”,簡(jiǎn)稱UCS(雙字節(jié)稱為UCS-2,四字節(jié)稱為UCS-4),俗稱Unicode字符集。Unicode字符集使用16bits表示一個(gè)字符,0—127的ASCII碼也擴(kuò)展為兩個(gè)字節(jié),用0-0x10FFFF來(lái)映射這些字符,可表示65536個(gè)字符,幾乎將世界上所有語(yǔ)言的常用字符收錄其中。標(biāo)準(zhǔn)的Unicode編碼稱為UTF-16,為了能使雙字節(jié)的Unicode在單字節(jié)處理的系統(tǒng)上正確傳輸,便使用類似MBCS的方式對(duì)Unicode進(jìn)行編碼,利用保留字符制定了三套編碼方式,分別為UTF-8、UTF-16、UTF-32。
2.4 關(guān)于UTF-8編碼
UTF-8是用1到4個(gè)字節(jié)編碼Unicode的可變長(zhǎng)度字符編碼,又稱萬(wàn)國(guó)碼。UTF-8用一個(gè)字節(jié)來(lái)表示字母和一些鍵盤(pán)上的符號(hào),當(dāng)用多字節(jié)表示時(shí)UTF-8設(shè)定了標(biāo)志位。
當(dāng)要表示的內(nèi)容是7位的時(shí)候就用一個(gè)字節(jié)存儲(chǔ),形如0xxxxxxx。首位0為標(biāo)志位,剩下碼位正好可以表示ASCII碼0—127的內(nèi)容。當(dāng)要表示的內(nèi)容在8到11位的時(shí)候就用兩個(gè)字節(jié)存儲(chǔ),形如110xxxxx 10xxxxxx。第一個(gè)字節(jié)的110和第二個(gè)字節(jié)的10為標(biāo)志位。當(dāng)要表示的內(nèi)容在12到16位的時(shí)候就用三個(gè)字節(jié)存儲(chǔ),形如1110xxxx 10xxxxxx 10xxxxxx。第一個(gè)字節(jié)的1110和第二、三個(gè)字節(jié)的10為標(biāo)志位,其余的碼位用來(lái)表示漢字。
UTF-8以8位為單元對(duì)UCS-2編碼模板,詳見(jiàn)表1。
表1 UTF-8對(duì)UCS-2編碼模板
Tab.1 UTF-8 to UCS-2 encoding templateendprint
UCS-2編碼值(H) UTF-8編碼結(jié)構(gòu)(B)
0000-007F 0xxxxxxx
0080-07FF 110xxxxx 10xxxxxx
0800-FFFF 1110xxxx 10xxxxxx 10xxxxxx
UTF-8以8位為單元對(duì)UCS-4編碼模板,詳見(jiàn)表2。
表2 UTF-8對(duì)UCS-4編碼模板
Tab.2 UTF-8 to UCS-4 encoding template
UCS-4編碼值(H) UTF-8編碼結(jié)構(gòu)(B)
0000 0000-0000 007F 0xxxxxxx
0000 0080-0000 07FF 110xxxxx 10xxxxxx
0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
0400 0000-7FFF FFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
2.5 關(guān)于BOM問(wèn)題
新建空文本文檔分別以ANSI、Unicode、Unicode big endian、UTF-8編碼格式存儲(chǔ),通過(guò)軟件Winhex解析文件,發(fā)現(xiàn)除ANSI編碼外,其他編碼方式都存在標(biāo)志頭字符,即根據(jù)不同的編碼方式在其文件頭添加規(guī)定的標(biāo)志字符用以區(qū)分。Unicode規(guī)范中稱該標(biāo)志字符為字節(jié)順序標(biāo)志(Byter Order Mark,BOM),俗稱標(biāo)簽。Winhex解析各種編碼類型的BOM,詳見(jiàn)表3。
表3 各種編碼類型BOM
Tab.3 BOM of various encoding types
編碼方式 BOM
ANSI 無(wú)
UTF-16(Unicode)/UCS-2 little endian FF FE
UTF-16(Unicode)/UCS-2 big endian FE FF
UTF-8 EF BB BF
3 軟件對(duì)文件編碼方式誤判的研究(Research
software for document encoding misjudgment)
在上述編碼知識(shí)的基礎(chǔ)上,下面針對(duì)記事本不能正常顯示“聯(lián)通”二字進(jìn)行分析。
3.1 記事本不能正常顯示“聯(lián)通”二字的研究
新建文本文檔1,輸入“聯(lián)通”二字,保存后退出,記事本是以默認(rèn)存儲(chǔ)的編碼方式(即ANSI)進(jìn)行保存的。再次打開(kāi)后會(huì)發(fā)現(xiàn)顯示為亂碼,點(diǎn)擊文件-另存為,發(fā)現(xiàn)該文件編碼方式顯示為UTF-8,說(shuō)明記事本認(rèn)為這是一個(gè)UTF-8編碼的文件。如果再新建一個(gè)文本文檔2,文件-打開(kāi),選中文本文檔1后,編碼方式選擇ANSI,打開(kāi)后便能正確顯示“聯(lián)通”二字,或者在新建文本文檔1中輸入“聯(lián)通”二字后,另存時(shí)編碼選擇為UTF-8,保存后退出,再次打開(kāi)也能正常顯示“聯(lián)通”二字。由此可以推斷這是編碼問(wèn)題導(dǎo)致的。
新建文本文檔,輸入“聯(lián)通”二字保存后,將文件導(dǎo)入Winhex查看其十六進(jìn)制編碼,發(fā)現(xiàn)為C1 AA CD A8(H),由此可以確定記事本是將“聯(lián)通”二字按照ANSI編碼方式進(jìn)行存儲(chǔ)的,因此再次打開(kāi)時(shí)選擇ANSI編碼,記事本將按照對(duì)應(yīng)方式解碼,“聯(lián)通”二字便可以正常顯示了。因此,若首次將“聯(lián)通”二字保存為UTF-8編碼方式,記事本按照UTF-8解碼(Decoding)時(shí)便能正確顯示了。
雙擊打開(kāi)文件,內(nèi)容顯示為亂碼,是因?yàn)橛浭卤緦NSI編碼存儲(chǔ)的文件用UTF-8編碼對(duì)應(yīng)的解碼方式進(jìn)行了解碼,致使錯(cuò)誤產(chǎn)生?!奥?lián)通”二字的ANSI編碼為C1 AA CD A8,如圖1所示,對(duì)應(yīng)二進(jìn)制代碼為1100 0001(C1),1010 1010(AA),1100 1101(CD),1010 1000(A8)。
圖1 “聯(lián)通”的ANSI編碼
Fig.1 ANSI encoding of Unicom
對(duì)于“聯(lián)”字,第一二個(gè)字節(jié)、第三四個(gè)字節(jié)的起始部分都是“110”和“10”,正好符合UTF-8規(guī)則里的雙字節(jié)模板。再次打開(kāi)文件時(shí),記事本其實(shí)根據(jù)二進(jìn)制代碼錯(cuò)誤判斷得出這是一個(gè)UTF-8編碼的文件,根據(jù)UTF-8規(guī)則去掉第一個(gè)字節(jié)的110和第二個(gè)字節(jié)的10,得到有效代碼為1101010,補(bǔ)上前導(dǎo)0后為0000 0000,0110 1010,即006A(H)在Unicode字符集中對(duì)應(yīng)小寫(xiě)字母j。同理,“通”字也按此解碼得到0368(H),在Unicode字符集中該編碼不對(duì)應(yīng)任何字符,因此致使記事本顯示為亂碼。
3.2 對(duì)記事本IsTextUTF8函數(shù)的研究
那么記事本究竟通過(guò)何種方式來(lái)判斷文件的編碼方式呢?
猜測(cè)是根據(jù)有無(wú)BOM判斷的。早期一些軟件并不在文件頭添加相應(yīng)的BOM文件,因此軟件不能單純通過(guò)BOM進(jìn)行判斷,不得不進(jìn)行模糊判斷。通過(guò)分析記事本的源代碼,可知記事本是通過(guò)nputf.c文件中的函數(shù)INT IsTextUTF8(LPSTR lpstrInputStream,INT iLen)進(jìn)行判斷的,對(duì)此函數(shù)作出如下分析。
//基于UTF-8雙字節(jié)模板編碼方式進(jìn)行判斷
//若為UTF-8編碼該函數(shù)返回真,若判斷只屬于前128個(gè)字符返回假,認(rèn)為是ASCII碼endprint
INT IsTextUTF8(LPSTR lpstrInputStream, INT iLen){
DWORD cOctets; //cOctets若是UTF-8,控制以10開(kāi)頭位段數(shù)
UCHAR chr;//一個(gè)字節(jié)長(zhǎng)度的字符類型chr
BOOL bAllAscii= TRUE;//若為真將按照ASCII碼標(biāo)準(zhǔn)進(jìn)行編碼
INT i; cOctets= 0;
for(i=0; i < iLen; i++) {
chr= *(lpstrInputStream+i);
if((chr&0x80) != 0) bAllAscii= FALSE;//0x80對(duì)應(yīng)二進(jìn)制是1000 0000,因?yàn)锳SCII碼只用了7位,首位為零,若是ASCII碼,該判斷值為假
if(cOctets == 0 {//當(dāng)字符不全由ACSII組成時(shí)
if(chr >= 0x80){//若大于0x80,說(shuō)明在ASCII碼之外
do {
chr <<= 1;//向左移位,用以判定是否符合UTF-8開(kāi)頭110 1110…的方式
cOctets++;//10開(kāi)頭位段數(shù)加一
}
while((chr&0x80) != 0);
cOctets--;//臨界處理
if(cOctets == 0) return FALSE;//若不符合形式11xx xxxx返回假
}
}
else {
if((chr&0xC0) != 0x80){//若八位組編碼符合10xx xxxx形式返回真,否則返回假
return FALSE;
}
cOctets--;//處理下一個(gè)八位組編碼
}
}//文本統(tǒng)計(jì)判斷結(jié)束
if(cOctets >0) {
return FALSE;//若后邊的八位組與首個(gè)八位組首位1的個(gè)數(shù)不滿足UTF-8的規(guī)律返回假
}
if(bAllAscii) {return FALSE;//若全部滿足符合ASCII碼,均小于128,返回假
}
return TRUE;//若不滿足上述情況返回真
}
由此可以看出,記事本正是通過(guò)UTF-8標(biāo)志位的特殊形式進(jìn)行判斷的,證實(shí)了“聯(lián)通”二字不能正常顯示原因的推斷。由此,可以得出結(jié)論“聯(lián)通”二字不能正常顯示是因?yàn)檎`將ANSI編碼方式判斷為UTF-8編碼,致使解碼錯(cuò)誤導(dǎo)致無(wú)法在相應(yīng)字符集找到字符,故顯示為亂碼。
4 更多不能被正確解碼的漢字(More characters
can not be correctly decoded)
綜上所述,是否符合研究得到形式的字符都會(huì)被錯(cuò)誤解碼呢?
根據(jù)誤判原因和UTF-8雙字節(jié)模板特點(diǎn),發(fā)現(xiàn)16進(jìn)制形式漢字字符,只要第一個(gè)字符為C或D,第三個(gè)字符為A或B的,都將被誤解碼。
Code 0 1 2 3 4 5 6 7 8 9 A B C D E F
C0A0饋 愧 潰 坤 昆 捆 困 括 擴(kuò) 廓 闊 垃 拉 喇 蠟
C0B0臘 辣 啦 萊 來(lái) 賴 藍(lán) 婪 欄 攔 籃 闌 蘭 瀾 讕 攬
C1A0痢 立 粒 瀝 隸 力 璃 哩 倆 聯(lián) 蓮 連 鐮 廉 憐
C1B0漣 簾 斂 臉 鏈 戀 煉 練 糧 涼 梁 粱 良 兩 輛 量
……
D0A0小 孝 校 肖 嘯 笑 效 楔 些 歇 蝎 鞋 協(xié) 挾 攜
D0B0邪 斜 脅 諧 寫(xiě) 械 卸 蟹 懈 泄 瀉 謝 屑 薪 芯 鋅
……
符合上述特點(diǎn)的漢字組成的高頻詞語(yǔ),如“笑臉”“謝謝”“兩輛”“拉力”等,它們不能正確的顯示會(huì)使人們產(chǎn)生困惑。在這些漢字之后繼續(xù)輸入其他漢字即可正常顯示,而全文僅由符合上述特點(diǎn)的漢字組成便會(huì)顯示為亂碼。這是由于INT IsTextUTF8(LPSTR lpstrInputStream,INT iLen)函數(shù)是基于統(tǒng)計(jì)判斷的,一篇文章只要有一組不符合UTF-8編碼形式軟件便會(huì)認(rèn)為文本是ANSI編碼。
5 結(jié)論(Conclusion)
本文通過(guò)分析發(fā)現(xiàn),漢字文本顯示為亂碼是軟件對(duì)文件編碼方式的錯(cuò)誤判斷造成的,發(fā)現(xiàn)了更多記事本不能正確顯示的漢字,由這些漢字組成的高頻詞語(yǔ)不能正確的顯示會(huì)使人們產(chǎn)生困惑。對(duì)軟件如何能正確判斷文件的編碼方式,還需要具體的程序來(lái)實(shí)現(xiàn)。
參考文獻(xiàn)(References)
[1] 馮靈清,楊懷卿,劉宇晶.常用編碼方式及其轉(zhuǎn)換格式[J].計(jì)算
機(jī)時(shí)代,2012(1):33-35.
[2] 張曉培,李祥.從Unicode到GBK的內(nèi)碼轉(zhuǎn)換[J].微計(jì)算機(jī)應(yīng)用,
2006,27(6):757-759.
[3] 邱發(fā)林,李偉,周紹景.Unicode及中文到Unicode轉(zhuǎn)換[J].科技
信息,2006(3):21-22.
作者簡(jiǎn)介:
王 玉(1993-),男,本科.研究領(lǐng)域:計(jì)算機(jī)應(yīng)用.
張永勝(1962-),男,教授,碩士生導(dǎo)師.研究領(lǐng)域:面向服務(wù)
計(jì)算,Web Services安全.endprint
INT IsTextUTF8(LPSTR lpstrInputStream, INT iLen){
DWORD cOctets; //cOctets若是UTF-8,控制以10開(kāi)頭位段數(shù)
UCHAR chr;//一個(gè)字節(jié)長(zhǎng)度的字符類型chr
BOOL bAllAscii= TRUE;//若為真將按照ASCII碼標(biāo)準(zhǔn)進(jìn)行編碼
INT i; cOctets= 0;
for(i=0; i < iLen; i++) {
chr= *(lpstrInputStream+i);
if((chr&0x80) != 0) bAllAscii= FALSE;//0x80對(duì)應(yīng)二進(jìn)制是1000 0000,因?yàn)锳SCII碼只用了7位,首位為零,若是ASCII碼,該判斷值為假
if(cOctets == 0 {//當(dāng)字符不全由ACSII組成時(shí)
if(chr >= 0x80){//若大于0x80,說(shuō)明在ASCII碼之外
do {
chr <<= 1;//向左移位,用以判定是否符合UTF-8開(kāi)頭110 1110…的方式
cOctets++;//10開(kāi)頭位段數(shù)加一
}
while((chr&0x80) != 0);
cOctets--;//臨界處理
if(cOctets == 0) return FALSE;//若不符合形式11xx xxxx返回假
}
}
else {
if((chr&0xC0) != 0x80){//若八位組編碼符合10xx xxxx形式返回真,否則返回假
return FALSE;
}
cOctets--;//處理下一個(gè)八位組編碼
}
}//文本統(tǒng)計(jì)判斷結(jié)束
if(cOctets >0) {
return FALSE;//若后邊的八位組與首個(gè)八位組首位1的個(gè)數(shù)不滿足UTF-8的規(guī)律返回假
}
if(bAllAscii) {return FALSE;//若全部滿足符合ASCII碼,均小于128,返回假
}
return TRUE;//若不滿足上述情況返回真
}
由此可以看出,記事本正是通過(guò)UTF-8標(biāo)志位的特殊形式進(jìn)行判斷的,證實(shí)了“聯(lián)通”二字不能正常顯示原因的推斷。由此,可以得出結(jié)論“聯(lián)通”二字不能正常顯示是因?yàn)檎`將ANSI編碼方式判斷為UTF-8編碼,致使解碼錯(cuò)誤導(dǎo)致無(wú)法在相應(yīng)字符集找到字符,故顯示為亂碼。
4 更多不能被正確解碼的漢字(More characters
can not be correctly decoded)
綜上所述,是否符合研究得到形式的字符都會(huì)被錯(cuò)誤解碼呢?
根據(jù)誤判原因和UTF-8雙字節(jié)模板特點(diǎn),發(fā)現(xiàn)16進(jìn)制形式漢字字符,只要第一個(gè)字符為C或D,第三個(gè)字符為A或B的,都將被誤解碼。
Code 0 1 2 3 4 5 6 7 8 9 A B C D E F
C0A0饋 愧 潰 坤 昆 捆 困 括 擴(kuò) 廓 闊 垃 拉 喇 蠟
C0B0臘 辣 啦 萊 來(lái) 賴 藍(lán) 婪 欄 攔 籃 闌 蘭 瀾 讕 攬
C1A0痢 立 粒 瀝 隸 力 璃 哩 倆 聯(lián) 蓮 連 鐮 廉 憐
C1B0漣 簾 斂 臉 鏈 戀 煉 練 糧 涼 梁 粱 良 兩 輛 量
……
D0A0小 孝 校 肖 嘯 笑 效 楔 些 歇 蝎 鞋 協(xié) 挾 攜
D0B0邪 斜 脅 諧 寫(xiě) 械 卸 蟹 懈 泄 瀉 謝 屑 薪 芯 鋅
……
符合上述特點(diǎn)的漢字組成的高頻詞語(yǔ),如“笑臉”“謝謝”“兩輛”“拉力”等,它們不能正確的顯示會(huì)使人們產(chǎn)生困惑。在這些漢字之后繼續(xù)輸入其他漢字即可正常顯示,而全文僅由符合上述特點(diǎn)的漢字組成便會(huì)顯示為亂碼。這是由于INT IsTextUTF8(LPSTR lpstrInputStream,INT iLen)函數(shù)是基于統(tǒng)計(jì)判斷的,一篇文章只要有一組不符合UTF-8編碼形式軟件便會(huì)認(rèn)為文本是ANSI編碼。
5 結(jié)論(Conclusion)
本文通過(guò)分析發(fā)現(xiàn),漢字文本顯示為亂碼是軟件對(duì)文件編碼方式的錯(cuò)誤判斷造成的,發(fā)現(xiàn)了更多記事本不能正確顯示的漢字,由這些漢字組成的高頻詞語(yǔ)不能正確的顯示會(huì)使人們產(chǎn)生困惑。對(duì)軟件如何能正確判斷文件的編碼方式,還需要具體的程序來(lái)實(shí)現(xiàn)。
參考文獻(xiàn)(References)
[1] 馮靈清,楊懷卿,劉宇晶.常用編碼方式及其轉(zhuǎn)換格式[J].計(jì)算
機(jī)時(shí)代,2012(1):33-35.
[2] 張曉培,李祥.從Unicode到GBK的內(nèi)碼轉(zhuǎn)換[J].微計(jì)算機(jī)應(yīng)用,
2006,27(6):757-759.
[3] 邱發(fā)林,李偉,周紹景.Unicode及中文到Unicode轉(zhuǎn)換[J].科技
信息,2006(3):21-22.
作者簡(jiǎn)介:
王 玉(1993-),男,本科.研究領(lǐng)域:計(jì)算機(jī)應(yīng)用.
張永勝(1962-),男,教授,碩士生導(dǎo)師.研究領(lǐng)域:面向服務(wù)
計(jì)算,Web Services安全.endprint
INT IsTextUTF8(LPSTR lpstrInputStream, INT iLen){
DWORD cOctets; //cOctets若是UTF-8,控制以10開(kāi)頭位段數(shù)
UCHAR chr;//一個(gè)字節(jié)長(zhǎng)度的字符類型chr
BOOL bAllAscii= TRUE;//若為真將按照ASCII碼標(biāo)準(zhǔn)進(jìn)行編碼
INT i; cOctets= 0;
for(i=0; i < iLen; i++) {
chr= *(lpstrInputStream+i);
if((chr&0x80) != 0) bAllAscii= FALSE;//0x80對(duì)應(yīng)二進(jìn)制是1000 0000,因?yàn)锳SCII碼只用了7位,首位為零,若是ASCII碼,該判斷值為假
if(cOctets == 0 {//當(dāng)字符不全由ACSII組成時(shí)
if(chr >= 0x80){//若大于0x80,說(shuō)明在ASCII碼之外
do {
chr <<= 1;//向左移位,用以判定是否符合UTF-8開(kāi)頭110 1110…的方式
cOctets++;//10開(kāi)頭位段數(shù)加一
}
while((chr&0x80) != 0);
cOctets--;//臨界處理
if(cOctets == 0) return FALSE;//若不符合形式11xx xxxx返回假
}
}
else {
if((chr&0xC0) != 0x80){//若八位組編碼符合10xx xxxx形式返回真,否則返回假
return FALSE;
}
cOctets--;//處理下一個(gè)八位組編碼
}
}//文本統(tǒng)計(jì)判斷結(jié)束
if(cOctets >0) {
return FALSE;//若后邊的八位組與首個(gè)八位組首位1的個(gè)數(shù)不滿足UTF-8的規(guī)律返回假
}
if(bAllAscii) {return FALSE;//若全部滿足符合ASCII碼,均小于128,返回假
}
return TRUE;//若不滿足上述情況返回真
}
由此可以看出,記事本正是通過(guò)UTF-8標(biāo)志位的特殊形式進(jìn)行判斷的,證實(shí)了“聯(lián)通”二字不能正常顯示原因的推斷。由此,可以得出結(jié)論“聯(lián)通”二字不能正常顯示是因?yàn)檎`將ANSI編碼方式判斷為UTF-8編碼,致使解碼錯(cuò)誤導(dǎo)致無(wú)法在相應(yīng)字符集找到字符,故顯示為亂碼。
4 更多不能被正確解碼的漢字(More characters
can not be correctly decoded)
綜上所述,是否符合研究得到形式的字符都會(huì)被錯(cuò)誤解碼呢?
根據(jù)誤判原因和UTF-8雙字節(jié)模板特點(diǎn),發(fā)現(xiàn)16進(jìn)制形式漢字字符,只要第一個(gè)字符為C或D,第三個(gè)字符為A或B的,都將被誤解碼。
Code 0 1 2 3 4 5 6 7 8 9 A B C D E F
C0A0饋 愧 潰 坤 昆 捆 困 括 擴(kuò) 廓 闊 垃 拉 喇 蠟
C0B0臘 辣 啦 萊 來(lái) 賴 藍(lán) 婪 欄 攔 籃 闌 蘭 瀾 讕 攬
C1A0痢 立 粒 瀝 隸 力 璃 哩 倆 聯(lián) 蓮 連 鐮 廉 憐
C1B0漣 簾 斂 臉 鏈 戀 煉 練 糧 涼 梁 粱 良 兩 輛 量
……
D0A0小 孝 校 肖 嘯 笑 效 楔 些 歇 蝎 鞋 協(xié) 挾 攜
D0B0邪 斜 脅 諧 寫(xiě) 械 卸 蟹 懈 泄 瀉 謝 屑 薪 芯 鋅
……
符合上述特點(diǎn)的漢字組成的高頻詞語(yǔ),如“笑臉”“謝謝”“兩輛”“拉力”等,它們不能正確的顯示會(huì)使人們產(chǎn)生困惑。在這些漢字之后繼續(xù)輸入其他漢字即可正常顯示,而全文僅由符合上述特點(diǎn)的漢字組成便會(huì)顯示為亂碼。這是由于INT IsTextUTF8(LPSTR lpstrInputStream,INT iLen)函數(shù)是基于統(tǒng)計(jì)判斷的,一篇文章只要有一組不符合UTF-8編碼形式軟件便會(huì)認(rèn)為文本是ANSI編碼。
5 結(jié)論(Conclusion)
本文通過(guò)分析發(fā)現(xiàn),漢字文本顯示為亂碼是軟件對(duì)文件編碼方式的錯(cuò)誤判斷造成的,發(fā)現(xiàn)了更多記事本不能正確顯示的漢字,由這些漢字組成的高頻詞語(yǔ)不能正確的顯示會(huì)使人們產(chǎn)生困惑。對(duì)軟件如何能正確判斷文件的編碼方式,還需要具體的程序來(lái)實(shí)現(xiàn)。
參考文獻(xiàn)(References)
[1] 馮靈清,楊懷卿,劉宇晶.常用編碼方式及其轉(zhuǎn)換格式[J].計(jì)算
機(jī)時(shí)代,2012(1):33-35.
[2] 張曉培,李祥.從Unicode到GBK的內(nèi)碼轉(zhuǎn)換[J].微計(jì)算機(jī)應(yīng)用,
2006,27(6):757-759.
[3] 邱發(fā)林,李偉,周紹景.Unicode及中文到Unicode轉(zhuǎn)換[J].科技
信息,2006(3):21-22.
作者簡(jiǎn)介:
王 玉(1993-),男,本科.研究領(lǐng)域:計(jì)算機(jī)應(yīng)用.
張永勝(1962-),男,教授,碩士生導(dǎo)師.研究領(lǐng)域:面向服務(wù)
計(jì)算,Web Services安全.endprint