關於編碼、unicode、utf-8的討論



不少國際化應用的讓我理解了這麼一個道理:Unicode是爲更方便的作國際化應用設計的,而Java核心的字符是基於UNICODE的,這一機制爲應用提供了對中文「字」的控制(而不是字節)。但若是不仔細理解其中的規範,這種自由反而會成爲累贅,從而致使更多的亂碼問題

什麼是編碼頁(code page)?
正如咱們所知,計算機只懂得數值。所以,當咱們想要它處理文本時,就把一門語言中每一個字符都賦以特定的值。簡單地說來,這種字符與數值的對照表就叫編碼頁。在這種狀況下,你可能常會聽到諸如字符集(charset),字符表(charmap),編碼(encoding),編碼字符集(coded character set)等術語。雖然彼此間還有一些細微的差別,爲理解的目的你能夠認爲它們都是指每種語言的字符、數值映射表。ASCII編碼頁就是一個很著名的例子,它把英文字母表和一些控制字符映射到一些特定的數值上去。


還有哪些編碼頁?圍繞着編碼頁有哪些問題?
ASCII編碼映射了127個字符,所以7位(bit)二進制數足夠用來表示127個字符。程序則典型地在8位的緩衝區內處理文本。這在處理其它的語言的編碼頁是會出問題。例如日語這種語言,有成千讓萬個字符,8位二制只能表示256個不一樣的字符,不可能惟一地表示每個日語字符。所以,人們用幾個字節來表示一個日語字符。如今,咱們又遇到另外一個問題。緩衝區的字節數不等於緩衝區中的字符數。每個簡單地字符串操做,都須要將字節組裝成字符。
認識到這種複雜性,開發人員利用一種叫寬字符(wide-character)的技術來處理外語字符串。寬字符基本上是16位或32位的數據類型。容量夠大,能知足亞洲語言的需求。處理字符串再也不使用8位的緩衝區(char *),而是使用16位的緩衝(unsigned short *)。所以每次移動指針,你均可以保證跳過了一個字符(而不是原先那多是半個)。
不一樣的開發商使用不一樣的編碼頁,給這帶來了混亂。也就是說,同一個日語字符,在一個機器上可能用0x95和0x5c兩個字節表示,而在另外的機器的上則多是0xc9和0xbd。這樣一事每次交換數據都要進行一次轉換(稱爲碼錶轉換(charmap conversion)或碼集轉換(codeset conversion))。

什麼是Unicode?它是如何解決這個問題的?
每一種語言的不一樣的編碼頁,增長了那些須要支持不一樣語言的軟件的複雜度。於是人們制定了一個世界標準,叫作unicode( http://www.unicode.org).Unicode爲每一個字符提供了惟一的特定數值,不論在什麼平臺上、不論在什麼軟件中,也不論什麼語言。也就是說,它世界上使用的全部字符都列出來,並給每個字符一個惟一特定數值。

什麼是UTF-8?它與UNICODE是一回事嗎?
Unicode的最初目標,是用1個16位的編碼來爲超過65000字符提供映射。但這還不夠,它不能覆蓋所有歷史上的文字,也不能解決傳輸的問題(implantation head-ache's),尤爲在那些基於網絡的應用中。已有的軟件必須作大量的工做來程序16位的數據。
所以,Unicode用一些基本的保留字符制定了三套編碼方式。它們分別是UTF-8,UTF-16和UTF-32。正如名字所示,在UTF-8中,字符是以8位序列來編碼的,用一個或幾個字節來表示一個字符。這種方式的最大好處,是UTF-8保留了ASCII字符的編碼作爲它的一部分,例如,在UTF-8和ASCII中,「A」的編碼都是0x41.
UTF-16和UTF-32分別是Unicode的16位和32位編碼方式。考慮到最初的目的,一般說的Unicode就是指UTF-16。在討論Unicode時,搞清楚哪一種編碼方式很是重要。Unicdoe相關的技術介紹參見 http://www.unicode.org/unicode/standard/principles.html. 話說這個VB6,非常無恥,竟然內置了支持Unicode的功能,也就是說,當你讀入一個字符串時,它根據本地缺省語言的對應關係將之轉換爲Unicode,輸出時,再從Unicode轉換爲本地編碼。一方面,它固然方便啦,隨便出個什麼語言的版本都好方便的,並且在Unicode的系統上,如NT,那它可就如魚得水,Unicode畢竟是軟件發展的方向,像如今中文Win9X使用的GBK內碼,實際上就是向着Unicode走了一大步。但是在另外一方面,這種支持實際上極大地延緩了字符串的處理時間!想一想看,若是咱們從文件裏讀一行並顯示,原本是很簡單的事情,但是在VB6裏面,實際上多了一段轉換到Unicode的時間,若是咱們用字符串從原文件裏讀一行,而後分析,再寫到目的文件裏去,實際上就多了兩重的時間(本地到Unicode,unicode到本地)。固然對於這種小事,高手們想必也都有處理的辦法(如用byte數組來代替字符串) 說了這麼一大堆Unicode的壞話,還沒說到正題呢,因爲VB6內置對Unicode的支持,而Unicode裏面分別和 GBK 以及Big5漢字都有對應關係,因此要實現轉換也只是一件小事,下面咱們就有請本次女主角出場。(嘩嘩嘩嘩……掌聲不絕。) 函數strConv! 這個美眉你們可能在VB5裏面也都見過的,她有一些保鏢,能夠幫她把字符串在Unicode和本地編碼之間轉換,而在VB6裏面呢,strConv又多了一個保鏢!你們請仔細看: strConv(string,conversion) `VB5 StrConv(string,conversion,LCID) `VB6 Java內核是unicode的,就連class文件也是,可是不少媒體,包括文件/流的保存方式  是使用字節流的。 所以Java要對這些字節流經行轉化。char是unicode的,而byte是字節.  Java中byte/char互轉的函數在sun.io的包中間有。其中ByteToCharConverter類是中調度,  能夠用來告訴你,你用的Convertor。其中兩個很經常使用的靜態函數是  public static ByteToCharConverter getDefault() ;  public static ByteToCharConverter getConverter(String encoding);  若是你不指定converter,則系統會自動使用當前的Encoding,GB平臺上用GBK,EN平臺上用  8859_1    咱們來就一個簡單的例子:  "你"的gb碼是:0xC4E3 ,unicode是0x4F60  你用:  --encoding="gb2312";  --byte b[]={(byte)"u00c4",(byte)"u00E3"};  --convertor=ByteToCharConverter.getConverter(encoding);  --char [] c=converter.convertAll(b);  --for(int i=0;i0xC4,0x00E3->0xE3,所以0xC4,0xE3被放進了  1.網頁傳參數不提倡用get方法,並且用戶能夠調整是否用utf-8發送 /////////// 這一行要注意了 2.建議jsp中最好不要用,實際上加不加這句都有實現中文正常顯示的方案,我認爲不加方便些,至少不用寫這些代碼,以下的配置我認爲可使中文正常顯示:  a.全部的javabean用iso8859-1編譯  b.jsp文件中不要寫以上charset=gb2312的語句(寫了反而錯) 這段更重要了,作後臺sql的都看看吧 咱們的目標是,任一國家的客戶端經過Form向Server發送信息,Server把信息存入數據庫中,客戶端在檢索時仍然可以看到本身發送的正確信息。事實上,咱們要保證,最終Server中的SQL語句中保存的時包含客戶端發送文字的正確Unicode編碼;DBC與數據庫通信時採用的編碼方式能包含客戶端發送的文字信息,事實上,最好讓JDBC直接使用UNICODE/UTF8與數據庫通信!這樣就能夠確保不會丟失信息;Server向客戶端發送的信息時也要採用不丟失信息的編碼方式,也能夠是Unicode/Utf8。  若是不指定Form的Enctype屬性,Form將把輸入的內容依照當前頁面的編碼字符集urlencode以後再提交,服務器端獲得是urlencoding的字符串。編碼後獲得的urlencoding字符串是與頁面的編碼相關的,如gb2312編碼的頁面提交"中文測試",獲得的是"%D6%D0%CE%C4%B2%E2%CA%D4",每一個"%"後跟的是16進制的字符串;而在UTF8編碼時獲得的倒是"%E4%B8%AD%E6%96%87%E6%B5%8B%E8%AF%95",由於GB2312編碼中一個漢字是16位的,而UTF8中一個漢字倒是24位的。中日韓三國的ie4以上瀏覽器均支持UTF8編碼,這種方案確定包涵了這三國語言,因此咱們若是讓Html頁面使用UTF8編碼那麼將至少能夠支持這三國語言。  可是,若是咱們html/Jsp頁面使用UTF8編碼,由於應用程序服務器可能不知道這種狀況,由於若是瀏覽器發送的信息不包含charset信息,至多Server知道讀到Accept-Language請求投標,咱們知道僅靠這個投標是不能獲知瀏覽器所採用編碼的,因此應用程序服務器不能正確解析提交的內容,爲何?由於Java中的全部字符串都是Unicode16位編碼的,HttpServletRequest.request(String)的功能就是把客戶端提交的Urlencode編碼的信息轉爲Unicode字符串,有些Server只能認爲客戶端的編碼和Server平臺相同,簡單地使用URLDecoder.decode(String)方法直接解碼,若是客戶端編碼剛好和Server相同,那麼就能夠獲得正確地字符串,不然,若是提交地字符串中包含了當地字符,那麼將會致使垃圾信息。
相關文章
相關標籤/搜索