計算機編碼方式--爲什麼總是亂碼?

在平時的文件處理過程中,有時會發現打開後的文件內容與預期不符,是一堆看不懂的符號,這主要是因爲文件存儲時選擇的編碼方式與文件打開時選擇的編碼方式不一樣。由於大部分編碼方式並沒有一個唯一標識,這也造成了文本處理工具無法自動識別編碼方式。接下來詳細介紹一下常見的幾種編碼方式

ASCII

世界上第一臺計算機誕生於美國,底層都採用二進制存儲。由於美國就26個英文字母,加上一些數字和符號,總共也沒多少字符,所以當時就設計了ASCII(American Standard Code for Information Interchange,美國信息交換標準碼),僅僅只需要一個字節,使用0-127,每一個數字表示一個字符,總共128個字符,這樣每一個字符都能編碼成一個數字,以二進制的形式進行存儲。常見的如數字1的編碼爲49,字母「a」的編碼爲97,字母「A」的編碼爲65。

ASCII碼錶

GB2312 & GBK & GB18030

隨着計算機在全世界的普及,很多國家都不使用英文,他們的文字在ASCII中是找不到的,所以他們使用128-255這127個數字來表示新的字符,叫做「擴展字符集」

等到了中國使用計算機的時候,不包括各種少數民族的文字,單單常用漢字就有6763個,一個字節已經遠遠詮釋不了上下五千年的悠久文化了。所以中國國家標準局基於ASCII設計了GB2312(信息交換用漢字編碼字符集),全部使用兩個字節表示,共收入漢字6763個和非漢字圖形字符682個,其中對於ASCII中的128個字符保持不變,在前面添加一個字節的0。並且對127及以下的符號、數字、英文字母都使用兩個字節重新編碼,叫做「全角」字符,而原來ASCII中的128個字符叫做「半角」字符。GB2312高位字節僅使用0xA1-0xF7範圍,低位字節使用0xA1-0xFE。

GBK編碼基於GB2312,新增了近20000個漢字,GBK僅要求高位字節大於127,對低位字節不做限制。

GB18030基於GBK,增加了幾千個少數民族的文字。

ANSI編碼就是英文使用ASCII編碼,中文使用GB2312編碼

Unicode

而隨着各個國家都基於ASCII進行不同的擴展,導致同樣的編碼在不同的國家表示不同的字符,互相都無法解析。ISO(International Organization for Standardization,國際標準化組織)主導設計了Unicode字符集,請注意Unicode僅僅是一種字符集,而不是編碼方式。

Unicode學名爲Universal Multiple-Octet Coded Character Set,簡稱USC,俗稱纔是Unicode,USC可以看作是"Unicode Character Set"的縮寫。Unicode規定了符號的二進制代碼,但是並沒有規定如何存儲,所以基於Unicode,又產生了各種不同的編碼方式。

UTF-8

UTF,Unicode Transformation Format:Unicode碼轉換格式。UTF-8是Unicode的一種實現方式,可以用1-4個字節表示一個字符,是一種變長的編碼方式,使用變長的編碼方式主要是在儘量多的覆蓋不同字符的情況下,減小存儲空間。(雖然可以對每一個字符都使用4個字節進行編碼,但同時也意味着存儲空間的巨大浪費)

變長編碼方式帶來的問題是,假設有3個字節,無法確定這3個字節是表示3個字符,還是表示1個字符,所以對UTF-8做了一些特殊的編碼規則:

  1. 對於單個字節的字符,最高位設爲0,後面7位爲這個字符的Unicode碼,與ASCII相同
  2. 對於n(n>1)字節字符,第一個字節的前n位都設置爲1,第n+1位設置爲0,後面字節的的前兩位一律設置爲10,其餘未說明的爲這個字符的Unicode碼
UTF-8編碼方式
Unicode碼(十六進制) UTF-8編碼(二進制)
0000 - 007F 0xxxxxxx
0080 - 07FF 110xxxxx 10xxxxxx
0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx

 

例如「你」的Unicode碼是 「4f 60」,屬於0800 - FFFF的範圍內,二進制表示爲01001111 01100000,對應的UTF-8則是11100100 10111101 10100000,使用十六進制表示則是「e4 bd a0」。

UTF-16

UTF-16也是一種變長的編碼方式,使用2個或4個字節表示一個字符,包括BMP和16個輔助平面。

BMP(Basic Multilingual Plane,基本多文種平面),USC-4根據最高位爲0的最高位字節分爲2^7=128個group,次高位2^8=256個plane,每個plane根據第三個字節分爲256行(rows),每行包括256個cells。其中group=0並且plane=0的被稱作BMP。

平面劃分:

  1. 0 - FFFF的爲BMP
  2. 10000 - 1FFFFD的空間稱作第一輔助平面(Supplementary Multilingual Plane, 簡稱SMP),擺放拼音文字(主要爲現時已不再使用的文字)及符號
  3. 20000 - 2FFFFD,第二輔助平面,又稱表意文字補充平面(Supplementary Ideographic Plane, 簡稱SIP)
  4. 30000-3FFFD,第三輔助平面,又稱表意文字第三平面 (Tertiary Ideographic Plane, 簡稱TIP)
  5. ...

UTF-16由於使用兩個字節爲基本單位,所以存在字節序的問題。例如「你」的Unicode碼是 「4f 60」,那麼應該存儲爲「4f 60」,還是「60 4f」呢?

Unicode中推薦的標記字符序的方式是BOM(Byte Order Mark,字節序標誌)。在Unicode編碼中,有一個叫做「ZERO WIDTH NO-BREAK SPACE」的字符,它的編碼是FEFF。在傳輸文本字節之前,建議先傳輸字符「ZERO WIDTH NO-BREAK SPACE」,如果接收者收到的是FEFF,則代表的是Big-Endian(「你」應該存儲爲「4f 60」),如果收到的是FFFE,則表達是Little-Endian(「你」存儲爲「60 4f」)。由於UTF-8是單字節的,所以不存在字節序的問題,規定可以用BOM來表示編碼方式,「EF BB BF」則表示是UTF-8編碼。

UTF-32

UTF-32規定所有字符均使用4個字節存儲,這種編碼方式在日常使用中比較少見,因爲不再BMP的字符都不常用。