Posted on 2005-04-04 11:04
風(fēng)太少 閱讀(176)
評(píng)論(0) 編輯 收藏
若想明白jsp開發(fā)過程中為什么會(huì)產(chǎn)生中文亂碼,我們先來看看unicode編碼。
Unicode (統(tǒng)一碼)顧名思義是一個(gè)將世界上各種文字統(tǒng)一在一起的東東。由美國各大電腦廠商組成的Unicode策進(jìn)會(huì)來推動(dòng)。目的,推廣一個(gè)世界通用的編碼體制,驚世界上所有常用的文字都涵蓋進(jìn)去,從而減少個(gè)電腦商開發(fā)國外市場遇到的問題。
為了將成千上萬的文字統(tǒng)統(tǒng)收集到一個(gè)共同的編碼機(jī)制下,在兼顧經(jīng)濟(jì)的原則下,不管是東方還是西方文字,每個(gè)字在Unicode中一律以兩個(gè)Bytes來表示,這樣至少有2的16次方65536種不同的組合,足以應(yīng)付目前絕大多數(shù)場合的需要。
基本上,計(jì)算機(jī)只是處理數(shù)字。它們指定一個(gè)數(shù)字,來儲(chǔ)存字母或其他字符。在創(chuàng)造Unicode之前,有數(shù)百種指定這些數(shù)字的編碼系統(tǒng)。沒有一個(gè)編碼可以包含足夠的字符:例如,單單歐州共同體就需要好幾種不同的編碼來包括所有的語言。即使是單一種語言,例如英語,也沒有哪一個(gè)編碼可以適用于所有的字母,標(biāo)點(diǎn)符號(hào),和常用的技術(shù)符號(hào)。
這些編碼系統(tǒng)也會(huì)互相沖突。也就是說,兩種編碼可能使用相同的數(shù)字代表兩個(gè)不同的字符,或使用不同的數(shù)字代表相同的字符。任何一臺(tái)特定的計(jì)算機(jī)(特別是服務(wù)器)都需要支持許多不同的編碼,但是,不論什么時(shí)候數(shù)據(jù)通過不同的編碼或平臺(tái)之間,那些數(shù)據(jù)總會(huì)有損壞的危險(xiǎn)。
Unicode給每個(gè)字符提供了一個(gè)唯一的數(shù)字,不論是什么平臺(tái),不論是什么程序,不論什么語言。Unicode標(biāo)準(zhǔn)已經(jīng)被這些工業(yè)界的領(lǐng)導(dǎo)們所采用,例如:Apple, HP, IBM, JustSystem, Microsoft, Oracle, SAP, Sun, Sybase, Unisys和其它許多公司。最新的標(biāo)準(zhǔn)都需要Unicode,例如XML, Java, ECMAScript (JavaScript), LDAP, CORBA 3.0, WML等等,并且,Unicode是實(shí)現(xiàn)ISO/IEC 10646的正規(guī)方式。許多操作系統(tǒng),所有最新的瀏覽器和許多其他產(chǎn)品都支持它。Unicode標(biāo)準(zhǔn)的出現(xiàn)和支持它工具的存在,是近來全球軟件技術(shù)最重要的發(fā)展趨勢。
將Unicode與客戶服務(wù)器或多層應(yīng)用程序和網(wǎng)站結(jié)合,比使用傳統(tǒng)字符集節(jié)省費(fèi)用。Unicode使單一軟件產(chǎn)品或單一網(wǎng)站能夠貫穿多個(gè)平臺(tái),語言和國家,而不需要重建。它可將數(shù)據(jù)傳輸?shù)皆S多不同的系統(tǒng),而無損壞。
在與Unicode相關(guān)的各技術(shù)文件中,經(jīng)常會(huì)看到ISO 10646和UCS這兩個(gè)名詞。
ISO是位于瑞士的國際標(biāo)準(zhǔn)局的縮寫。
UCS為ISO頒布的第10646號(hào)標(biāo)準(zhǔn) Universal Character Set,就是世界通用字符集。
UCS通用字符集采用4個(gè)Bytes來編碼,將世界上所有的官用和商用編碼大小通吃,一網(wǎng)打盡。Unicode自1991年便和ISO的UCS小組密切配合,讓Unicode和ISO 10646保持一致。因此Unicode 自2.0版開始,便和 ISO 10646-1使用相同的編碼。
康熙字典中的漢字有4萬7千,如果再加上里面沒有的簡體字,和不同寫法的日文字,那么 Unicode6萬多的分配空間,光用來分配漢字就顯得捉禁見晝,更別說什么泰文,阿拉伯等其他文字了。針對(duì)這個(gè)問題Unicode和UCS采用了[中日韓文整合](CJK Unification)的解決方案,把中日韓筆畫詳盡的漢字用同一個(gè)單碼表示。
經(jīng)過[中日韓文整合]的Unicode稱為統(tǒng)漢字Unihan。
完整的Unicode4.0版可由http://www.unicode.org/Public/UNIDATA/Unihan.txt 下載。
UTF (Unicode/UCS Transformation Format),Unicode推薦使用UTF-8和UTF-16兩種格式其中8和16指的是Bits數(shù)而不是Bytes數(shù)。
UTF-16基本就是Unicode雙字節(jié)的實(shí)現(xiàn),加上一個(gè)應(yīng)付未來需要的擴(kuò)充編碼機(jī)制(很少用)
UTF-8 是一種不等幅的編碼方式,英數(shù)字(Ascii字碼)保持原狀,完全不受影響(因此不需要做轉(zhuǎn)換),而其他漢字資料須透過程序來轉(zhuǎn)換,會(huì)[變胖],因?yàn)槊總€(gè)字需要額外一個(gè)或兩個(gè)Bytes來編碼。
UCS字符集中,有UCS-2和UCS-4等編碼方式其中的2和4指的是bytes數(shù),對(duì)應(yīng)UTF-8和UTF-16.
UCS-2基本和Unicode雙byte 編碼差不多
UCS-4四 byte編碼表示一個(gè)字,在每個(gè) UCS-2前面加上兩個(gè)空白的Byte,便可得到對(duì)應(yīng)的 UCS-4。
Unicode的空間分配:
以下Unicode區(qū)位碼均以16進(jìn)制表示
Unicode的前256個(gè)字符和ISO-8859-1(西歐字母)完全相同,其中前半段就是Ascii(u+0000到u+00FF)。每個(gè)ISO-8859-1碼前面補(bǔ)上一個(gè)空byte(0x00)后才是相應(yīng)的Unicode碼。
和我們切身相關(guān)的Unihan主要分布在u+3400到u+F9FFF之間,GB2312和BIG5主要分布在u+4E00到U+9FFF之間。
UTF-8的編碼原理和特性:
知道了西歐字符和漢字在Unicode中的位置后,來看看UTF-8
U+0000~U+007E 1 _ _ _ _ _ _ _ (7bits)
U+0080~U+07FF 1 1 0_ _ _ _ _ 1 0_ _ _ _ _ _ (11bits)
U+0800~U+FFFF 1 1 1 0 _ _ _ _ 1 0 _ _ _ _ _ _ 1 0 _ _ _ _ _ _ (16bits)
看一看Unicode三種格式提出自由的bits(下劃線空位)是否足以用來代表區(qū)位中各Unicode碼,剛好夠用。
那么當(dāng)程序處理UTF-8編碼文件時(shí),如何得知一個(gè)字符的疆界落在哪里?還有到底他是以三種形式那一中出現(xiàn)呢?
每個(gè)以UTF-8編碼的字符,不管是以一、二、三個(gè)bytes出現(xiàn),第一個(gè)byte前端都清楚地標(biāo)示了該字符的byte總數(shù)。如110種有兩個(gè)1,代表這種字符是以第二種方式出現(xiàn),由兩個(gè)bytes組成。而1110有三個(gè)1,表示這種字符一點(diǎn)種方式出現(xiàn),由三個(gè)字節(jié)組成。
每個(gè)多重byte的UTF-8編碼有一個(gè)共同的通性,即其中的第二個(gè)第三個(gè)byte, 一律以10兩個(gè)bits開頭。由于其中的最高位總設(shè)成1,可以很容易和那些在UTF-8中只用一個(gè)Byte的ASCII字元區(qū)分開來,方便偵錯(cuò)。
因?yàn)樯鲜鲈O(shè)計(jì)特點(diǎn),UTF-8和Unicode之間,可以很容易做雙向自由轉(zhuǎn)換,而不會(huì)丟失任何資料。
有關(guān)解決方法,明天有時(shí)間我會(huì)貼上相關(guān)代碼出來..........
解決辦法:亂碼問題在 NT操作系統(tǒng)我沒怎么碰到過,但是在UNIX 或LINUX系統(tǒng)上出現(xiàn)的比較多
由于操作系統(tǒng)和使用環(huán)境不一樣,產(chǎn)生亂碼的方式也不一樣,但是如果掌握了上面的Unicode 編碼原理,自己仔細(xì)分析一下,很多問題便可迎刃而解。
下面看看幾個(gè)常見的例子。
1. 如果一些網(wǎng)站服務(wù)器例如Tomcat 如果遇到中文亂碼問題,可以修改conf目錄下的server.xml
<Connector port="8080" maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100" debug="0"connectionTimeout="20000" disableUploadTimeout="true" URIEncoding="GBK"/>
URIENcoding 設(shè)成GBK或GB2312
2. 表單中或傳遞字符串:本來輸入的漢字是正常的,但是提交后再顯示出來是亂碼,因?yàn)樘峤坏囊话闶?ISO8859編碼,所以顯示的時(shí)候要轉(zhuǎn)成GB2312編碼:
String S=new String(rs.getString("news").getBytes("gb2312"),"ISO8859_1");
//rs為待轉(zhuǎn)換的字符串
然后使用S字符串的值就可以了
3. 有的服務(wù)器端的語言環(huán)境如果設(shè)成簡體中文的也可以解決此類問題
4. 插入數(shù)據(jù)庫中的字符是亂碼
看看數(shù)據(jù)庫中支持的是何種編碼方式,用類似2中的方式作一下轉(zhuǎn)換即可。
5. 總之,用jsp開發(fā),碰到亂碼,你得分析是讀的時(shí)候發(fā)生亂碼,還是寫的時(shí)候發(fā)生亂碼,用2中的轉(zhuǎn)換,基本就能解決問題,有些時(shí)候?qū)懙臅r(shí)候做一次轉(zhuǎn)換,例如:
String S=new String(rs.getString("news").getBytes("gb2312"),"ISO8859_1");
//讀的時(shí)候在轉(zhuǎn)換回來
String S=new String(rs.getString("news").getBytes("ISO8859_1"),"GB2312");
或者把ISO8859-1和GB2312 的位置換一下,自己多試試,就能找到解決問題的辦法。