我們在平時編程序時,經常會遇到亂碼問題。
往往會讓我們措手不及。經常是百度谷歌了一通,依然不能很好解決。
想從根源上理解亂碼問題是如何產生的,就應該去深刻理解亂碼問題產生的根本原因:
首先,任何字符在計算機系統中的存儲都一定是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 |
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等遠程終端)
任何一個環節 編碼錯誤都可能導致亂碼。