簡單了解下為什麼會亂碼,以及怎麼恢復

電腦是如何存儲字元的?

​ 大學都學過電腦相關的基礎知識,電腦只能計算二進位數據,因為二進位表示起來最方便。電腦電子元器件表示兩個狀態很簡單,比如高壓和低壓,對應的就是1和0。如果設計出10種狀態,那麼電腦的設計會相當複雜。

​ 電腦想存儲我們現實世界的字元,也就是我們常用的漢子或者字母。最簡單的方法就是把每個字元都對應一個數字,數字都能轉為二進位,這樣相當於電腦間接的存儲了字元。實際上,電腦科學家們也的確是這麼做的。由此,便誕生了各種字符集,各個國家的字元都有對應的數字。

都有哪些字符集

​ 電腦發明之初,沒有考慮那麼多。作為現代電腦的發源地,當時也只考慮了美國的需求。所以只需要128個字元,稱之為ASCII編碼或者ASCII字符集(叫法不同而已,但是我覺得叫字符集更準確)。128個字元,如果用數字一一對應,一共只需7位二進位數字。電腦存儲的最小單位是byte,即8位。ASCII字符集把最高位設置為0,用剩下的7位來表示字元。下圖便展示了ASCII中,數字與字元的對應關係。

img

​ 圖中把ASCII字符集分為了兩大部分,列印和非列印。列印部分好解釋,就是會輸出在顯示設備上的,可以看看我們的鍵盤上,一般也都會有這些字元。非列印部分更多的是控制目的。比如NUL表示空字元,\n表示換行,\r表示回車等。

​ 對於美國來說,ASCII是夠用了,但是其他很多國家顯然就不夠用了。下面簡單說說一些常見的。ISO 8859-1和Windows-1252。這兩個都加入了西歐字元,兩者基本一樣,ISO 8859-1號稱是用於西歐國家的標準字符集,但是Windows-1252更常用些。

​ 中文的第一個標準字符集是GB2312,有大約7000個漢字和一些罕用詞和繁體字。其使用兩個位元組表示漢字。GBK建立在GB2312的基礎上,並向下兼容。共計包含了21000個漢字,其中包含了繁體字。GB18030進一步增強了GBK,同樣可以向下兼容,共包含了76000個字元,其中有很多少數民族字元,以及中日韓統一字元。但是兩個位元組已經表示不了GB18030中的所有字元了,GB18030使用了長編碼,有的字元是兩個位元組,有的是四個位元組。兩個位元組的編碼中,表示範圍和GBK一樣。除了以上表示中文的字符集外,還有個Big5,是針對繁體字的,廣泛應用於灣灣省和香港那邊。

​ 前面說了這麼多,是不是覺得很麻煩。不同的國家地區,還得用不用的字符集。前面講到的所有字符集統稱為非Unicode字符集。為了解決每個國家不同字符集間的不兼容現狀,便有了Unicode字符集。它做了一件事,就是給世界上所有字元都分配了一個唯一的數字編號,有110多萬,但大部分都在0x0000~0xFFFF之間,即65536個。

​ 這些數字編號一般用16進位表示,但是要注意,只是分配了個數字編號,並不像上面的非Unicode字符集一樣,這個數字也表示字元對應的二進位。至於Unicode字符集中,每個字元對應的二進位是多少,有幾種不同的方案,主要有UTF-8、UTF-16、UTF-32。

​ UTF-32最簡單,也符合我們的正常邏輯。數字編號的二進位形式,就是這個字元對應的二進位。缺點就是,每個字元都用四個位元組表示,顯然對於常用字元這是非常浪費的。UTF-16和GB18030一樣,有個用兩個位元組有的用四個位元組。UTF-8使用最廣,其使用的是變長位元組,每個字元使用的位元組個數與Unicode中的數字編號有關。編號小的用的位元組就少,編號大的用的位元組就多,位元組個數從1~4不等。

亂碼怎麼恢復

​ 看到這裡,為什麼亂碼相信你肯定知道了。無非就是使用了不同的字符集,導致解析錯誤。那麼該怎麼恢復亂碼呢?如果你知道原編碼方式最好,直接切換成對應的字符集即可。比如在一些可以切換編碼方式的文本編輯器里、HTML的原資訊設置、IDE的設置等。

​ 但是如果不知道的話,也沒什麼太好的方式,只能一個個嘗試了。我們可以寫個簡單的小程式,通過遍歷常見字符集,來試著解析出亂碼的原有格式。以Java為例:String newStr = new String(str.getBytes(charsets[i]),charsets[j])。這句程式碼的意思就是:假設亂碼str原來是charsets[j]編碼的,被錯誤解析為charsets[i]編碼的。在嘗試前,切記要對原文件做備份,因為多次錯誤的解析和轉換,可能很難再恢復成正常的字元了。

Tags: