|
世界上的各地區(qū)都有本地的語(yǔ)言。地區(qū)差異直接導(dǎo)致了語(yǔ)言環(huán)境的差異。在開(kāi)發(fā)一個(gè)國(guó)際化程序的過(guò)程中,處理語(yǔ)言問(wèn)題就顯得很重要了。
這是一個(gè)世界范圍內(nèi)都存在的問(wèn)題,所以,Java提供了世界性的解決方法。本文描述的方法是用于處理中文的,但是,推而廣之,對(duì)于處理世界上其它國(guó)家和地區(qū)的語(yǔ)言同樣適用。
漢字是雙字節(jié)的。所謂雙字節(jié)是指一個(gè)雙字要占用兩個(gè)BYTE的位置(即16位),分別稱(chēng)為高位和低位。中國(guó)規(guī)定的漢字編碼為GB2312,這是強(qiáng)制性的,目前幾乎所有的能處理中文的應(yīng)用程序都支持GB2312。GB2312包括了一二級(jí)漢字和9區(qū)符號(hào),高位從0xa1到0xfe,低位也是從0xa1到0xfe,其中,漢字的編碼范圍為0xb0a1到0xf7fe。
另外有一種編碼,叫做GBK,但這是一份規(guī)范,不是強(qiáng)制的。GBK提供了20902個(gè)漢字,它兼容GB2312,編碼范圍為0x8140到0xfefe。GBK中的所有字符都可以一一映射到Unicode 2.0。
在不久的將來(lái),中國(guó)會(huì)頒布另一種標(biāo)準(zhǔn):GB18030-2000(GBK2K)。它收錄了藏、蒙等少數(shù)民族的字型,從根本上解決了字位不足的問(wèn)題。注意:它不再是定長(zhǎng)的。其二字節(jié)部份與GBK兼容,四字節(jié)部分是擴(kuò)充的字符、字形。它的首字節(jié)和第三字節(jié)從0x81到0xfe,二字節(jié)和第四字節(jié)從0x30到0x39。
本文不打算介紹Unicode,有興趣的可以瀏覽“http://www.unicode.org/”查看更多的信息。Unicode有一個(gè)特性:它包括了世界上所有的字符字形。所以,各個(gè)地區(qū)的語(yǔ)言都可以建立與Unicode的映射關(guān)系,而Java正是利用了這一點(diǎn)以達(dá)到異種語(yǔ)言之間的轉(zhuǎn)換。
在JDK中,與中文相關(guān)的編碼有:
表1 JDK中與中文相關(guān)的編碼列表
編碼名稱(chēng) | 說(shuō)明 |
ASCII | 7位,與ascii7相同 |
ISO8859-1 | 8-位,與 8859_1,ISO-8859-1,ISO_8859-1,latin1...等相同 |
GB2312-80 | 16位,與gb2312,gb2312-1980,EUC_CN,euccn,1381,Cp1381, 1383, Cp1383, ISO2022CN,ISO2022CN_GB...等相同 |
GBK | 與MS936相同,注意:區(qū)分大小寫(xiě) |
UTF8 | 與UTF-8相同 |
GB18030 | 與cp1392、1392相同,目前支持的JDK很少 |
在實(shí)際編程時(shí),接觸得比較多的是GB2312(GBK)和ISO8859-1。
為什么會(huì)有“?”號(hào)
上文說(shuō)過(guò),異種語(yǔ)言之間的轉(zhuǎn)換是通過(guò)Unicode來(lái)完成的。假設(shè)有兩種不同的語(yǔ)言A和B,轉(zhuǎn)換的步驟為:先把A轉(zhuǎn)化為Unicode,再把Unicode轉(zhuǎn)化為B。
舉例說(shuō)明。有GB2312中有一個(gè)漢字“李”,其編碼為“C0EE”,欲轉(zhuǎn)化為ISO8859-1編碼。步驟為:先把“李”字轉(zhuǎn)化為Unicode,得到“674E”,再把“674E”轉(zhuǎn)化為ISO8859-1字符。當(dāng)然,這個(gè)映射不會(huì)成功,因?yàn)镮SO8859-1中根本就沒(méi)有與“674E”對(duì)應(yīng)的字符。
當(dāng)映射不成功時(shí),問(wèn)題就發(fā)生了!當(dāng)從某語(yǔ)言向Unicode轉(zhuǎn)化時(shí),如果在某語(yǔ)言中沒(méi)有該字符,得到的將是Unicode的代碼“/uffffd”(“/u”表示是Unicode編碼,)。而從Unicode向某語(yǔ)言轉(zhuǎn)化時(shí),如果某語(yǔ)言沒(méi)有對(duì)應(yīng)的字符,則得到的是“0x3f”(“?”)。這就是“?”的由來(lái)。
例如:把字符流buf =“0x80 0x40 0xb0 0xa1”進(jìn)行new String(buf, "gb2312")操作,得到的結(jié)果是“/ufffd/u554a”,再println出來(lái),得到的結(jié)果將是“?啊”,因?yàn)椤?x80 0x40”是GBK中的字符,在GB2312中沒(méi)有。
再如,把字符串String="/u00d6/u00ec/u00e9/u0046/u00bb/u00f9"進(jìn)行new String (buf.getBytes("GBK"))操作,得到的結(jié)果是“3fa8aca8a6463fa8b4”,其中,“/u00d6”在“GBK”中沒(méi)有對(duì)應(yīng)的字符,得到“3f”,“/u00ec”對(duì)應(yīng)著“a8ac”,“/u00e9”對(duì)應(yīng)著“a8a6”,“0046”對(duì)應(yīng)著“46”(因?yàn)檫@是ASCII字符),“/u00bb”沒(méi)找到,得到“3f”,最后,“/u00f9”對(duì)應(yīng)著“a8b4”。把這個(gè)字符串println一下,得到的結(jié)果是“?ìéF?ù”。看到?jīng)]?這里并不全是問(wèn)號(hào),因?yàn)镚BK與Unicode映射的內(nèi)容中除了漢字外還有字符,本例就是最好的明證。
所以,在漢字轉(zhuǎn)碼時(shí),如果發(fā)生錯(cuò)亂,得到的不一定都是問(wèn)號(hào)噢!不過(guò),錯(cuò)了終究是錯(cuò)了,50步和100步并沒(méi)有質(zhì)的差別。
或者會(huì)問(wèn):如果源字符集中有,而Unicode中沒(méi)有,結(jié)果會(huì)如何?回答是不知道。因?yàn)槲沂诸^沒(méi)有能做這個(gè)測(cè)試的源字符集。但有一點(diǎn)是肯定的,那就是源字符集不夠規(guī)范。在Java中,如果發(fā)生這種情況,是會(huì)拋出異常的。
什么是UTF
UTF,是Unicode Text Format的縮寫(xiě),意為Unicode文本格式。對(duì)于UTF,是這樣定義的:
(1)如果Unicode的16位字符的頭9位是0,則用一個(gè)字節(jié)表示,這個(gè)字節(jié)的首位是“0”,剩下的7位與原字符中的后7位相同,如“/u0034”(0000 0000 0011 0100),用“34” (0011 0100)表示;(與源Unicode字符是相同的);
(2)如果Unicode的16位字符的頭5位是0,則用2個(gè)字節(jié)表示,首字節(jié)是“110”開(kāi)頭,后面的5位與源字符中除去頭5個(gè)零后的最高5位相同;第二個(gè)字節(jié)以“10”開(kāi)頭,后面的6位與源字符中的低6位相同。如“/u025d”(0000 0010 0101 1101),轉(zhuǎn)化后為“c99d”(1100 1001 1001 1101);
(3)如果不符合上述兩個(gè)規(guī)則,則用三個(gè)字節(jié)表示。第一個(gè)字節(jié)以“1110”開(kāi)頭,后四位為源字符的高四位;第二個(gè)字節(jié)以“10”開(kāi)頭,后六位為源字符中間的六位;第三個(gè)字節(jié)以“10”開(kāi)頭,后六位為源字符的低六位;如“/u9da7”(1001 1101 1010 0111),轉(zhuǎn)化為“e9b6a7”(1110 1001 1011 0110 1010 0111);
可以這么描述Java程序中Unicode與UTF的關(guān)系,雖然不絕對(duì):字符串在內(nèi)存中運(yùn)行時(shí),表現(xiàn)為Unicode代碼,而當(dāng)要保存到文件或其它介質(zhì)中去時(shí),用的是UTF。這個(gè)轉(zhuǎn)化過(guò)程是由writeUTF和readUTF來(lái)完成的。
好了,基礎(chǔ)性的論述差不多了,下面進(jìn)入正題。
先把這個(gè)問(wèn)題想成是一個(gè)黑匣子。先看黑匣子的一級(jí)表示:
input(charsetA)->process(Unicode)->output(charsetB)
簡(jiǎn)單,這就是一個(gè)IPO模型,即輸入、處理和輸出。同樣的內(nèi)容要經(jīng)過(guò)“從charsetA到unicode再到charsetB”的轉(zhuǎn)化。
再看二級(jí)表示:
SourceFile(jsp,Java)->class->output
在這個(gè)圖中,可以看出,輸入的是jsp和Java源文件,在處理過(guò)程中,以Class文件為載體,然后輸出。再細(xì)化到三級(jí)表示:
jsp->temp file->class->browser,os console,db
app,servlet->class->browser,os console,db
這個(gè)圖就更明白了。Jsp文件先生成中間的Java文件,再生成Class。而Servlet和普通App則直接編譯生成Class。然后,從Class再輸出到瀏覽器、控制臺(tái)或數(shù)據(jù)庫(kù)等。
JSP:從源文件到Class的過(guò)程
Jsp的源文件是以“.jsp”結(jié)尾的文本文件。在本節(jié)中,將闡述JSP文件的解釋和編譯過(guò)程,并跟蹤其中的中文變化。
1、JSP/Servlet引擎提供的JSP轉(zhuǎn)換工具(jspc)搜索JSP文件中用<%@ page contentType ="text/html; charset=<Jsp-charset>"%>中指定的charset。如果在JSP文件中未指定<Jsp-charset>,則取JVM中的默認(rèn)設(shè)置file.encoding,一般情況下,這個(gè)值是ISO8859-1;
2、jspc用相當(dāng)于“Javac 主站蜘蛛池模板: 国产无套在线观看视频 | 一级特黄视频 | 亚洲视频91| 毛片韩国 | 国产视频久 | 九九手机视频 | 波多野衣结在线精品二区 | 麻豆娜娜 | 欧美日韩亚洲一区二区精品 | 青青国产成人久久91 | 久久怡红院亚欧成人影院 | 国产福利最新手机在线观看 | 久久六月丁香婷婷婷 | 午夜dj观看在线影院 | 午夜久久久精品 | 91综合久久久久婷婷 | 欧美一区二区三区激情啪啪 | 欧美日韩一区二区三在线 | 午夜精品乱人伦小说区 | 久草社区在线 | 青青草久热精品视频在线观看 | 国产成人91精品 | 精品午夜久久福利大片免费 | 尤物网址在线观看日本 | 麻豆国产精品免费视频 | 国产乱子伦露脸在线 | 国产欧美91 | 久久久91 | 日韩在线精品 | 精品视频一二三区 | 欧美成人午夜视频 | 欧美日韩不卡码一区二区三区 | sihu国产午夜精品一区二区三区 | 亚洲你我色 | 婷婷国产成人久久精品激情 | 成人福利在线 | 黄色wwwcom | 在线播放亚洲精品富二代91 | 国产精品日韩欧美在线第3页 | 亚洲精品第四页中文字幕 | 国产福利在线视频 |