理解字符亂碼問題

我們在平時編程序時,經常會遇到亂碼問題。

往往會讓我們措手不及。經常是百度谷歌了一通,依然不能很好解決。


想從根源上理解亂碼問題是如何產生的,就應該去深刻理解亂碼問題產生的根本原因:


首先,任何字符在計算機系統中的存儲都一定是01序列。這一點我們一定要時刻認識到。如果你什麼都不告訴計算機,計算機自然會以01序列的方式讀取文件。至於如何理解這些01序列到底代表人類語言中的哪個字,這就需要一套預先定義好的識別規範。


不幸的是,這世界居然不只一種識別規範。有gbk,有utf-8,還有latin等等字符編碼規範。如果你按照A字符規範將你的字符編碼成01序列,然後存儲到文件。而我用B字符規範理解這個文件中的 01序列,自然就出現了亂碼。


以utf-8編碼規範爲例:

Bits of
code point
First
code point
Last
code point
Bytes in
sequence
Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6
  7 U+0000 U+007F 1 0xxxxxxx
11 U+0080 U+07FF 2 110xxxxx 10xxxxxx
16 U+0800 U+FFFF 3 1110xxxx 10xxxxxx 10xxxxxx
21 U+10000 U+1FFFFF 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
26 U+200000 U+3FFFFFF 5 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
31 U+4000000 U+7FFFFFFF 6 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
按照utf-8編碼規範,一個字(人類語言中的字),可能會被編碼到計算機中,對應1-6個字節。


1.我們來作一個實驗:

在linux系統中用vim 創建一個文件test1,只輸入“abcd"  後保存。

用hexdump test1查看這個文件中的內容。

可以看到內容如下:

lisendong@ubuntu:/tmp$ hexdump ./test1
0000000 6261 6463 000a                         
0000005

很容易看出 61 是 ‘a'的asc碼,62 是 ‘b'的asc碼,63 是 ‘c'的asc碼,64 是 ‘d'的asc碼。

至於那個'0a' 自然就是有名的換行符。

顯然一個字符只佔1個byte。這是最簡單的字符。

不管你誰發明的編碼規範,26個英文字母的編碼你不能改。這是大家公認的。

所以代碼裏如果全使用英文,是不會出現亂碼的。所以我現在註釋也都用英文寫咯。


2.我們再來看一個例子:

用vim創建一個文件test2,敲入如下命令

:set fileencoding=utf-8

只輸入"我"後保存。

用hexdump test2查看文件內容。

lisendong@ubuntu:/tmp$ hexdump test2
0000000 88e6 0a91                              
0000004

可以看出“我”字在utf-8編碼規範中被編碼爲3個bytes: e6 88 91

在這個網站 http://www.ltg.ed.ac.uk/~richard/utf-8.cgi?input=e6+88+91&mode=bytes 查看這三個bytes被理解爲是utf-8的時候,對應的是什麼樣子的字符。可以看出清晰的“我”字。


3.繼續做實驗:

用vim創建文件test3,敲入

:set fileencoding=gbk

只輸入“我”後保存。

用hexdump test3查看文件內容:

lisendong@ubuntu:/tmp$ hexdump test3
0000000 d2ce 000a                              
0000003

看出“我”字在gbk編碼規範中被編碼爲2個bytes: ce d2

沒有找到比較好的網站,就先用這個吧:http://www.cs.nyu.edu/~yusuke/tools/unicode_to_gb2312_or_gbk_table.html 查到 ced2 確實對應的是“我”字。

U+6210  
b3c9

ced2

bde4

91e1*

91e2*

e3de

bbf2

eaa8

d5bd

91e3*

c6dd

eaa9

91e4*

91e5*

91e6*

eaaa

這個時候,如果你的系統的編碼是utf-8 (通過$LANG環境變量設置) 那你直接cat test3 會發現亂碼字符。。。

lisendong@ubuntu:/tmp$ cat test3

很容易理解。就好比你跟你哥們考試的時候傳紙條,你哥們把他想的答案用日語寫在紙條上,你讀取的時候用中文理解,顯然要完蛋。


總結以上,解決亂碼問題的最有效的方法爲:

1、首先檢查數據的源頭到底是什麼編碼(比如數據是存在文件中的,就去讀幾個字符出來試解碼一下,看看到底是什麼編碼規範)。

2、看看數據流從源頭到你看到亂碼 這之間,經過了那幾層。比如你用vim打開一個文件,那數據流至少經過 以下幾個組件:

      源文件->vim軟件->操作系統->終端(包括putty等遠程終端)

      任何一個環節 編碼錯誤都可能導致亂碼。     









發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章