<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    優(yōu)秀是一種習(xí)慣

     

    Java基礎(chǔ)——孫鑫談Java中文亂碼問題產(chǎn)生原因分析(一)

    聲明:本文轉(zhuǎn)載自:http://www.phome.asia/article/814.html

    在計算機(jī)中,只有二進(jìn)制的數(shù)據(jù),不管數(shù)據(jù)是在內(nèi)存中,還是在外部存儲設(shè)備上。對于我們所看到的字符,也是以二進(jìn)制數(shù)據(jù)的形式存在的。不同字符對應(yīng)二進(jìn)制數(shù)的規(guī)則,就是字符的編碼。字符編碼的集合稱為字符集。

    常用字符集

    1. ASCII

    在早期的計算機(jī)系統(tǒng)中,使用的字符非常少,這些字符包括26個英文字母、數(shù)字符號和一些常用符號(包括控制符號),對這些字符進(jìn)行編碼,用1個字節(jié)就足夠了(1個字節(jié)可以表示28=256種字符)。然而實(shí)際上,表示這些字符,只使用了1個字節(jié)的7位,這就是ASCII編碼1ASCII

    ASCIIAmerican Standard Code for Information Interchange,美國信息互換標(biāo)準(zhǔn)代碼),是基于常用的英文字符的一套電腦編碼系統(tǒng)。每一個ASCII與一個8位(bit)二進(jìn)制數(shù)對應(yīng)。其最高位是0,相應(yīng)的十進(jìn)制數(shù)是0127。例如,數(shù)字字符“0”的編碼用十進(jìn)制數(shù)表示就是48。另有128個擴(kuò)展的ASCII碼,最高位都是1,由一些圖形和畫線符號組成。ASCII是現(xiàn)今最通用的單字節(jié)編碼系統(tǒng)。

    ASCII用一個字節(jié)來表示字符,最多能夠表示256種字符。隨著計算機(jī)的普及,許多國家都將本地的語言符號引入到計算機(jī)中,擴(kuò)展了計算機(jī)中字符的范圍,于是就出現(xiàn)了各種不同的字符集。

    2ISO8859-1

    因?yàn)?/span>ASCII碼中缺少£、ü和許多書寫其他語言所需的字符,為此,可以通過指定128以后的字符來擴(kuò)展ASCII碼。國際標(biāo)準(zhǔn)組織(ISO)定義了幾個不同的字符集,它們是在ASCII碼基礎(chǔ)上增加了其他語言和地區(qū)需要的字符。其中最常用的是ISO8859-1,通常叫做Latin-1Latin-1包括了書寫所有西方歐洲語言不可缺少的附加字符,其中0127的字符與ASCII碼相同。ISO 8859另外定義了14個適用于不同文字的字符集(8859-28859-15)。這些字符集共享0127ASCII碼,只是每個字符集都包含了128255的其他字符。

    3GB2312GBK

    GB2312是中華人民共和國國家標(biāo)準(zhǔn)漢字信息交換用編碼,全稱《信息交換用漢字編碼字符集-基本集》,標(biāo)準(zhǔn)號為GB2312-80,是一個由中華人民共和國國家標(biāo)準(zhǔn)總局發(fā)布的關(guān)于簡化漢字的編碼,通行于中國大陸和新加坡,簡稱國標(biāo)碼。

    因?yàn)橹形淖址麛?shù)量較多,所以采用兩個字節(jié)來表示一個字符,分別稱為高位和低位。為了和ASCII碼有所區(qū)別,中文字符的每一個字節(jié)的最高位都用1來表示。GB2312字符集是幾乎所有的中文系統(tǒng)和國際化的軟件都支持的中文字符集,也是最基本的中文字符集。它包含了大部分常用的一、二級漢字和9區(qū)的符號,其編碼范圍是高位0xa1-0xfe,低位也是0xa1-0xfe,漢字從0xb0a1開始,結(jié)束于0xf 7fe

    為了對更多的字符和符號進(jìn)行編碼,由前電子部科技質(zhì)量司和國家技術(shù)監(jiān)督局標(biāo)準(zhǔn)化司于199512月頒布了GBKK擴(kuò)展的漢語拼音第一個字母)編碼規(guī)范,在新的編碼系統(tǒng)里,除了完全兼容GB2312外,還對繁體中文、一些不常用的漢字和許多符號進(jìn)行了編碼。它也是現(xiàn)階段Windows和其他一些中文操作系統(tǒng)的默認(rèn)字符集,但并不是所有的國際化軟件都支持該字符集。不過要注意的是GBK不是國家標(biāo)準(zhǔn),它只是規(guī)范。GBK字符集包含了20 902個漢字,其編碼范圍是0x8140-0xfefe

    每個國家(或區(qū)域)都規(guī)定了計算機(jī)信息交換用的字符編碼集,這就造成了交流上的困難。想像一下,你發(fā)送一封中文郵件給一位遠(yuǎn)在西班牙的朋友,當(dāng)郵件通過網(wǎng)絡(luò)發(fā)送出去的時候,你所書寫的中文字符會按照本地的字符集GBK轉(zhuǎn) 換為二進(jìn)制編碼數(shù)據(jù),然后發(fā)送出去。當(dāng)你的朋友接收到郵件(二進(jìn)制數(shù)據(jù))后,查看信件時,會按照他所用系統(tǒng)的字符集,將二進(jìn)制編碼數(shù)據(jù)解碼為字符,然而由 于兩種字符集之間編碼的規(guī)則不同,導(dǎo)致轉(zhuǎn)換出現(xiàn)亂碼。這是因?yàn)椋诓煌淖址g,同樣的數(shù)字可能對應(yīng)了不同的符號,也可能在另一種字符集中,該數(shù)字沒 有對應(yīng)符號。

    為了解決上述問題,統(tǒng)一全世界的字符編碼,由Unicode協(xié)會制定并發(fā)布了Unicode編碼。

    4Unicode

    Unicode(統(tǒng)一的字符編碼標(biāo)準(zhǔn)集)使用065 535的雙字節(jié)無符號數(shù)對每一個字符進(jìn)行編碼。它不僅包含來自英語和其他西歐國家字母表中的常見字母和符號,也包含來自古斯拉夫語、希臘語、希伯來語、阿拉伯語和梵語的字母表。另外還包含漢語和日語的象形漢字和韓國的Hangul音節(jié)表。

    目前已經(jīng)定義了40 000多個不同的Unicode字符,剩余25 000個空缺留給將來擴(kuò)展使用。其中大約20 000個字符用于漢字,另外11 000左右的字符用于韓語音節(jié)。Unicode0255的字符與ISO8859-1中的一致。

    Unicode編碼對于英文字符采取前面加“0”字節(jié)的策略實(shí)現(xiàn)等長兼容。如“a”ASCII碼為0x61Unicode碼就為0x000x61

    5UTF-8

    使用Unicode編碼,一個英文字符要占用兩個字節(jié),在Internet上,大多數(shù)的信息都是用英文來表示的,如果都采用Unicode編碼,將會使數(shù)據(jù)量增加一倍。為了減少存儲和傳輸英文字符數(shù)據(jù)的數(shù)據(jù)量,可以使用UTF-8編碼。

    UTF-8全稱是Eight-bit UCS Transformation FormatUCSUniversal Character Set,通用字符集,UCS是所有其他字符集標(biāo)準(zhǔn)的一個超集)。對于常用的字符,即0127ASCII字符,UTF-8用一個字節(jié)來表示,這意味著只包含7ASCII字符的字符數(shù)據(jù)在ASCIIUTF-8兩種編碼方式下是一樣的。如果字符對應(yīng)的Unicode碼是0x0000,或在0x00800x007f之間,對應(yīng)的UTF-8編碼是兩個字節(jié),如果字符對應(yīng)的Unicode碼在0x08000xffff之間,對應(yīng)的UTF-8編碼是三個字節(jié)。因?yàn)橹形淖址?/span>Unicode編碼在0x08000xffff之間,所以數(shù)據(jù)如果是中文,采用UTF-8編碼數(shù)據(jù)量會增加50%

    UnicodeUTF-8轉(zhuǎn)換的規(guī)則簡述如下:

    1)如果Unicode編碼的16位二進(jìn)制數(shù)的前9位是0,則UTF-8編碼用1個字節(jié)來表示,這個字節(jié)的首位是“0”,剩下的7位與原二進(jìn)制數(shù)據(jù)的后7位相同。例如:

    Unicode編碼:"u0061 = 00000000 01100001

    UTF-8編碼:01100001 = 0x61

    2)如果Unicode編碼的16位二進(jìn)制數(shù)的頭5位是0,則UTF-8編碼用2個字節(jié)來表示,首字節(jié)以“110”開頭,后面的5位與原二進(jìn)制數(shù)據(jù)除去前5個零后的最高5位相同;第二個字節(jié)以“10”開頭,后面的6位與原二進(jìn)制數(shù)據(jù)中的低6位相同。例如:

    Unicode編碼:"u00A9 = 00000000 10101001

    UTF-8編碼:11000010 10101001 = 0xC2 0xA9

    3)如果不符合上述兩個規(guī)則,則用三個字節(jié)表示。第一個字節(jié)以“1110”開頭,后四位為原二進(jìn)制數(shù)據(jù)的高四位;第二個字節(jié)以“10”開頭,后六位為原二進(jìn)制數(shù)據(jù)中間的六位;第三個字節(jié)以“10”開頭,后六位為原二進(jìn)制數(shù)據(jù)的低六位。例如:

    Unicode編碼:"u4E2D = 01001110 00101101

    UTF-8編碼:11100100 10111000 10101101 = 0xE4 0xB8 0xAD

    UTF-8編碼的多字節(jié)串中,第一個字節(jié)開頭“1”的數(shù)目就是整個字符串中字節(jié)的數(shù)目。

    17.1.2 對亂碼產(chǎn)生過程的分析

    為了讓使用Java語言編寫的程序能在各種語言的平臺下運(yùn)行,Java在其內(nèi)部使用Unicode字符集來表示字符,這樣就存在Unicode字符集和本地字符集進(jìn)行轉(zhuǎn)換的過程。當(dāng)在Java中讀取字符數(shù)據(jù)的時候,需要將本地字符集編碼的數(shù)據(jù)轉(zhuǎn)換為Unicode編碼,而在輸出字符數(shù)據(jù)的時候,則需要將Unicode編碼轉(zhuǎn)換為本地字符集編碼。

    例如,在中文系統(tǒng)下,從控制臺讀取一個字符,實(shí)際上讀取的是GBK編碼0xD6D0,在Java語言中要將GBK編碼轉(zhuǎn)換為Unicode編碼0x4E2D,此時,在內(nèi)存中,字符對應(yīng)的數(shù)值就是0x4E2D,當(dāng)我們向控制臺輸出字符時,Java語言將Unicode編碼再轉(zhuǎn)換為GBK編碼,輸出到控制臺,中文系統(tǒng)再根據(jù)GBK字符集畫出相應(yīng)的字符。

    從上述過程來看,讀取和寫入的過程是可逆的,那么理應(yīng)不會出現(xiàn)中文亂碼問題。然而,實(shí)際應(yīng)用的情形,比上述過程要復(fù)雜得多。在Web應(yīng)用中,通常都包括了瀏覽器、Web服務(wù)器、Web應(yīng)用程序和數(shù)據(jù)庫等部分,每一部分都有可能使用不同的字符集,從而導(dǎo)致字符數(shù)據(jù)在各種不同的字符集之間轉(zhuǎn)換時,出現(xiàn)亂碼的問題。

    Java語言中,不同字符集編碼的轉(zhuǎn)換,都是通過Unicode編碼作為中介來完成的。例如,GBK編碼的字符要轉(zhuǎn)換為ISO-8859-1(同ISO8859-1)編碼,其過程如下:

    1)因?yàn)樵?/span>Java中的字符,都是用Unicode來表示的,所以GBK編碼的字符要轉(zhuǎn)換為Unicode表示:0xD6D0->0x4E2D

    2)將字符Unicode編碼轉(zhuǎn)換為ISO-8859-1編碼,因?yàn)?/span>Unicode編碼0x4E2DISO-8859-1中沒有對應(yīng)的編碼,于是得到0x3f,也就是字符“?”

    下面的代碼演示了這一過程:

    //GBK編碼的字符轉(zhuǎn)換為Unicode編碼表示

    String str="";

    //將字符Unicode編碼轉(zhuǎn)換為ISO-8859-1編碼

    byte[] b=str.getBytes("ISO-8859-1");

    for(int i=0;i<b.length;i++)

    {

           //輸出轉(zhuǎn)換后的二進(jìn)制代碼。

           System.out.print(b[i]);

    }

    當(dāng)從Unicode編碼向某個字符集轉(zhuǎn)換時,如果在該字符集中沒有對應(yīng)的編碼,則得到0x3f(即問號字符?)。這就是為什么有時候我們輸入的是中文,在輸出時卻變成了問號。

    從其他字符集向Unicode編碼轉(zhuǎn)換時,如果這個二進(jìn)制數(shù)在該字符集中沒有標(biāo)識任何的字符,則得到的結(jié)果是0xfffd。例如一個GBK的編碼值0x8140,從GB2312Unicode轉(zhuǎn)換,然而由于0x8140不在GB2312字符集的編碼范圍(0xa1a1-0xfefe),當(dāng)然也就沒有對應(yīng)任何的字符,所以轉(zhuǎn)換后會得到0xfffd。下面的代碼演示了這一過程。

    //構(gòu)造一個二進(jìn)制數(shù)據(jù)。

    byte[] buf={(byte)0x81,(byte)0x40,(byte)0xb0,(byte)0xa1};

    //將二進(jìn)制數(shù)據(jù)按照GB2312Unicode編碼轉(zhuǎn)換。

    String str=new String(buf,"GB2312");

           

    for(int i=0;i<str.length();i++)

    {

        //取出字符串中的每個Unicode編碼的字符。

        char ch=str.charAt(i);

        //將該字符對應(yīng)的Unicode編碼以十六進(jìn)制的形式輸出。

        System.out.print(Integer.toHexString((int)ch));

        System.out.print("--");

        //輸出該字符。

        System.out.println(ch);

    }

    posted on 2009-08-12 09:41 黃土高坡 閱讀(446) 評論(0)  編輯  收藏


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     

    導(dǎo)航

    統(tǒng)計

    常用鏈接

    留言簿

    隨筆分類

    隨筆檔案

    收藏夾

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 97无码免费人妻超级碰碰夜夜| 亚洲sss综合天堂久久久| 精品国产免费观看久久久| 91麻豆国产免费观看| a级毛片毛片免费观看久潮喷| 亚洲Av永久无码精品黑人| 亚洲六月丁香六月婷婷色伊人| 亚洲AV永久精品爱情岛论坛| 亚洲国产黄在线观看| 国产在线观看免费视频播放器| 曰批视频免费30分钟成人| 久久w5ww成w人免费| 野花香高清在线观看视频播放免费 | 亚洲色一区二区三区四区| 亚洲av永久无码精品表情包| 国产亚洲一区区二区在线| 四虎www成人影院免费观看| 91久久成人免费| 91青青青国产在观免费影视| 免费在线观看一级片| 最新久久免费视频| 9久热这里只有精品免费| 一级人做人爰a全过程免费视频| 特级毛片全部免费播放a一级| 亚洲av成人中文无码专区| 中文字幕亚洲精品无码| 亚洲av无码国产综合专区| 亚洲最大在线视频| 亚洲国产精品成人精品小说| 久久精品国产99国产精品亚洲| 亚洲婷婷综合色高清在线| 亚洲欧洲尹人香蕉综合| 亚洲国产精品免费在线观看| 亚洲中文字幕在线无码一区二区| 一区二区三区亚洲| 亚洲欧洲日产v特级毛片| 精品亚洲AV无码一区二区| 亚洲色无码国产精品网站可下载| 一区二区亚洲精品精华液| 亚洲爆乳少妇无码激情| 最近中文字幕完整版免费高清|