??? 今天在做ajax的portlet的時候用response返回數據遇到了中文亂碼的問題,給我們帶來了很大的麻煩。unicode、utf8、gb2312、gbk之間關系如何,互有什么淵源,對于unicode來說在將來不遠的幾年里, 它已經很接近于取代 ASCII
與 Latin-1 編碼的位置了.
它不僅允許你處理處理事實上存在于地球上的任何語言文字,
而且提供了一個全面的數學與技術符號集,
因此可以簡化科學信息交換。于是痛下決心好好研究研究研究這些編碼之間的關系,以便以后能夠比較輕松的解決之類的問題。經過在網上查詢資料研究得出如下關于utf-8與unicode編碼的心得:
??? 最開始美國是用Ascii來保存英文字母和一些字符(空格,標點符號等等)的。
??? 后來中國人們得到計算機時,已經沒有可以利用的字節狀態來表示漢字,況且有6000多個常用漢字需要保存呢。我們就用兩個字節來表示漢字信息這樣我們就可以組合出大約7000多個簡體漢字了。在這些編碼里,我們還把數學符號、羅馬希臘的 字母、日文的假名們都編進去了,連在 ASCII 里本來就有的數字、標點、字母都統統重新編了兩個字節長的編碼,這就是常說的"全角"字符,而原來在127號以下的那些就叫"半角"字符了。這就是GB2312。
??? 再后來,我們把第一個字節是大于127就固定表示這是一個漢字的開始。結果擴展之后的編碼方案被稱為 GBK 標準,GBK 包括了 GB2312 的所有內容,同時又增加了近20000個新的漢字(包括繁體字)和符號。后來少數民族也要用電腦了,于是我們再擴展,又加了幾千個新的少數民族的字,GBK 擴成了 GB18030。
??? Unicode 只是分配整數給字符的編碼表,但是UNICODE 在制訂時沒有考慮與任何一種現有的編碼方案保持兼容,這使得 GBK 與UNICODE 在漢字的內碼編排上完全是不一樣的,沒有一種簡單的算術方法可以把文本內容從UNICODE編碼和另一種編碼進行轉換,這種轉換必須通過查表來進行。UNICODE 是用兩個字節來表示為一個字符,他總共可以組合出65535不同的字符,這大概已經可以覆蓋世界上所有文化的符號。如果還不夠也沒有關系,ISO已經準備 了UCS-4方案,說簡單了就是四個字節來表示一個字符,這樣我們就可以組合出21億個不同的字符出來(最高位有其他用途).
??? UNICODE 來到時,一起到來的還有計算機網絡的興起,UNICODE 如何在網絡上傳輸也是一個必須考慮的問題,于是面向傳輸的眾多 UTF(UCS Transfer Format)標準出現了,顧名思義,UTF8就是每次8個位傳輸數據,而UTF16就是每次16個位,只不過為了傳輸時的可靠性,從UNICODE到 UTF時并不是直接的對應,而是要過一些算法和規則來轉換。這就是我們應用諸如tomcat的服務器其中的配置文件會有編碼的設置,一般的默認設置就是utf8。
??? 在網絡里傳遞信息時有一個很重要的問題,就是對于數據高低位的解讀方式,一些計算機是采用低位先發送的方法,例如我們PC機采用的 x86 架構,而另一些是采用高位先發送的方式,在網絡中交換數據時,為了核對雙方對于高低位的認識是否是一致的,采用了一種很簡便的方法,就是在文本流的開始時 向對方發送一個標志符——如果之后的文本是高位在位,那就發送"FEFF",反之,則發送"FFFE"。
??? 講到這里,我們再順便說說一個很著名的奇怪現象:當你在 windows 的記事本里新建一個文件,輸入"聯通"兩個字之后,保存,關閉,然后再次打開,你會發現這兩個字已經消失了,代之的是幾個亂碼!呵呵......其實這是因為GB2312編碼與UTF8編碼產生了編碼沖撞的原因。
??? utf8 與 unicode 的轉換標準如下:
Unicode
UTF-8
0000 - 007F
0xxxxxxx
0080 - 07FF
110xxxxx 10xxxxxx
0800 - FFFF
1110xxxx 10xxxxxx 10xxxxxx
如:中醫藥的 unicode 碼為:\u4e2d\u533b\u836f,去掉 \u 后為:? 4e2d? 533b? 836f
這三個字的二進制編碼分別為:
0100? 1110? 00 10? 1101
0101? 0011? 00 11? 1011
1000? 0011? 01 10? 1111? 他們都是大于0800小于ffff,所以適用第三種模板
將他們分別編碼為:
1110 0100 10 111000 10 101101?? ---> ??? e4b8ad
1110 0101 10 001100 10 111011?? --->???? e58cbb
1110 1000 10 001101 10 101111?? --->???? e88daf
e4b8ad、e58cbb、e88daf分別為:中醫藥 的utf8編碼
??? 而當你新建一個文本文件時,記事本的編碼默認是ANSI, 如果你在ANSI的編碼輸入漢字,那么他實際就是GB系列的編碼方式,在這種編碼下,"聯通"的內碼是: \u8054\u901a
c1 1100 0001
aa 1010 1010
cd 1100 1101
a8 1010 1000
注 意到了嗎?第一二個字節、第三四個字節的起始部分的都是"110"和"10",正好與UTF8規則里的兩字節模板是一致的,于是再次打開記事本時,記事本 就誤認為這是一個UTF8編碼的文件,讓我們把第一個字節的110和第二個字節的10去掉,我們就得到了"00001 101010",再把各位對齊,補上前導的0,就得到了"0000 0000 0110 1010",不好意思,這是UNICODE的006A,也就是小寫的字母"j",而之后的兩字節用UTF8解碼之后是0368,這個字符什么也不是。這就 是只有"聯通"兩個字的文件沒有辦法在記事本里正常顯示的原因。
??? 而如果你在"聯通"之后多輸入幾個字,其他的字的編碼不見得又恰好是110和10開始的字節,這樣再次打開時,記事本就不會堅持這是一個utf8編碼的文件,而會用ANSI的方式解讀之,這時亂碼又不出現了。
而如果你在"聯通"之后多輸入幾個字,其他的字的編碼不見得又恰好是110和10開始的字節,這樣再次打開時,記事本就不會堅持這是一個utf8編碼的文件,而會用ANSI的方式解讀之,這時亂碼又不出現了。 ?
??? 最開始美國是用Ascii來保存英文字母和一些字符(空格,標點符號等等)的。
??? 后來中國人們得到計算機時,已經沒有可以利用的字節狀態來表示漢字,況且有6000多個常用漢字需要保存呢。我們就用兩個字節來表示漢字信息這樣我們就可以組合出大約7000多個簡體漢字了。在這些編碼里,我們還把數學符號、羅馬希臘的 字母、日文的假名們都編進去了,連在 ASCII 里本來就有的數字、標點、字母都統統重新編了兩個字節長的編碼,這就是常說的"全角"字符,而原來在127號以下的那些就叫"半角"字符了。這就是GB2312。
??? 再后來,我們把第一個字節是大于127就固定表示這是一個漢字的開始。結果擴展之后的編碼方案被稱為 GBK 標準,GBK 包括了 GB2312 的所有內容,同時又增加了近20000個新的漢字(包括繁體字)和符號。后來少數民族也要用電腦了,于是我們再擴展,又加了幾千個新的少數民族的字,GBK 擴成了 GB18030。
??? Unicode 只是分配整數給字符的編碼表,但是UNICODE 在制訂時沒有考慮與任何一種現有的編碼方案保持兼容,這使得 GBK 與UNICODE 在漢字的內碼編排上完全是不一樣的,沒有一種簡單的算術方法可以把文本內容從UNICODE編碼和另一種編碼進行轉換,這種轉換必須通過查表來進行。UNICODE 是用兩個字節來表示為一個字符,他總共可以組合出65535不同的字符,這大概已經可以覆蓋世界上所有文化的符號。如果還不夠也沒有關系,ISO已經準備 了UCS-4方案,說簡單了就是四個字節來表示一個字符,這樣我們就可以組合出21億個不同的字符出來(最高位有其他用途).
??? UNICODE 來到時,一起到來的還有計算機網絡的興起,UNICODE 如何在網絡上傳輸也是一個必須考慮的問題,于是面向傳輸的眾多 UTF(UCS Transfer Format)標準出現了,顧名思義,UTF8就是每次8個位傳輸數據,而UTF16就是每次16個位,只不過為了傳輸時的可靠性,從UNICODE到 UTF時并不是直接的對應,而是要過一些算法和規則來轉換。這就是我們應用諸如tomcat的服務器其中的配置文件會有編碼的設置,一般的默認設置就是utf8。
??? 在網絡里傳遞信息時有一個很重要的問題,就是對于數據高低位的解讀方式,一些計算機是采用低位先發送的方法,例如我們PC機采用的 x86 架構,而另一些是采用高位先發送的方式,在網絡中交換數據時,為了核對雙方對于高低位的認識是否是一致的,采用了一種很簡便的方法,就是在文本流的開始時 向對方發送一個標志符——如果之后的文本是高位在位,那就發送"FEFF",反之,則發送"FFFE"。
??? 講到這里,我們再順便說說一個很著名的奇怪現象:當你在 windows 的記事本里新建一個文件,輸入"聯通"兩個字之后,保存,關閉,然后再次打開,你會發現這兩個字已經消失了,代之的是幾個亂碼!呵呵......其實這是因為GB2312編碼與UTF8編碼產生了編碼沖撞的原因。
??? utf8 與 unicode 的轉換標準如下:
Unicode
UTF-8
0000 - 007F
0xxxxxxx
0080 - 07FF
110xxxxx 10xxxxxx
0800 - FFFF
1110xxxx 10xxxxxx 10xxxxxx
如:中醫藥的 unicode 碼為:\u4e2d\u533b\u836f,去掉 \u 后為:? 4e2d? 533b? 836f
這三個字的二進制編碼分別為:
0100? 1110? 00 10? 1101
0101? 0011? 00 11? 1011
1000? 0011? 01 10? 1111? 他們都是大于0800小于ffff,所以適用第三種模板
將他們分別編碼為:
1110 0100 10 111000 10 101101?? ---> ??? e4b8ad
1110 0101 10 001100 10 111011?? --->???? e58cbb
1110 1000 10 001101 10 101111?? --->???? e88daf
e4b8ad、e58cbb、e88daf分別為:中醫藥 的utf8編碼
??? 而當你新建一個文本文件時,記事本的編碼默認是ANSI, 如果你在ANSI的編碼輸入漢字,那么他實際就是GB系列的編碼方式,在這種編碼下,"聯通"的內碼是: \u8054\u901a
c1 1100 0001
aa 1010 1010
cd 1100 1101
a8 1010 1000
注 意到了嗎?第一二個字節、第三四個字節的起始部分的都是"110"和"10",正好與UTF8規則里的兩字節模板是一致的,于是再次打開記事本時,記事本 就誤認為這是一個UTF8編碼的文件,讓我們把第一個字節的110和第二個字節的10去掉,我們就得到了"00001 101010",再把各位對齊,補上前導的0,就得到了"0000 0000 0110 1010",不好意思,這是UNICODE的006A,也就是小寫的字母"j",而之后的兩字節用UTF8解碼之后是0368,這個字符什么也不是。這就 是只有"聯通"兩個字的文件沒有辦法在記事本里正常顯示的原因。
??? 而如果你在"聯通"之后多輸入幾個字,其他的字的編碼不見得又恰好是110和10開始的字節,這樣再次打開時,記事本就不會堅持這是一個utf8編碼的文件,而會用ANSI的方式解讀之,這時亂碼又不出現了。
而如果你在"聯通"之后多輸入幾個字,其他的字的編碼不見得又恰好是110和10開始的字節,這樣再次打開時,記事本就不會堅持這是一個utf8編碼的文件,而會用ANSI的方式解讀之,這時亂碼又不出現了。 ?