計算機編碼總結

編碼發展歷史簡介

第一階段 ASCII

在計算機中,全部的數據只多是0或者1(用高電平和低電平分別表示1和0),那麼咱們一般看到的字符也就只能用0和1來表示呀。因而科學家們(這裏指的是美國的科學家)就想出一個辦法,把一個特定的數字對應一個特定的字母進行存儲和傳輸,好比我須要存儲字母a,那麼我存入一個數字97(即在計算機中存入二進制(01100001),這個過程叫作編碼(encode),而咱們在讀取數據的時候,當遇到97時,咱們就讓計算機顯示字母a,這個過程叫作解碼(decode)。
爲了你們在數據傳輸的時候不至於產生誤會,那麼咱們須要讓全部的人都使用數字97來表明字母a,因此須要制定一份標準(即碼錶),最開始的這個標準叫作ASCII碼錶。
規則html

  • 全部的控制字符(好比CR回車、DEL刪除等)編碼在0-31範圍以及127中。
  • 把全部的標點符號,英文大小寫所有放在32-126範圍中。
  • 防止之後出現須要補充的狀況,把128-255位這麼多位置留出來,應該足夠用了吧!因此設置一個字節8位二進制,把這個標準叫American Standard Code for Information Interchange(美國標準信息交換代碼,簡寫爲ASCII),標準制定結束。

等等,咱們的中文字呢?
美國的"磚家"沒有考慮那麼久遠呢!這就是後面出現那麼多問題的根源所在啊。
實現方式
第一位始終未0,後面7位表示0-127的範圍,一個數字對應一個字母或者標點符號,亦或者控制符號,即全部的ASCII碼的統一形式爲0xxxx xxxx。python

第二階段 GB2312,GBK, BIG5 Latin1, ISO-8859-1, JIS, ANSI...

計算機技術到了歐洲,歐洲人發現怎麼咱們的那麼多符號沒有編進去啊!
因此歐洲"磚家"坐到了一塊兒,開始討論。
發現既然美國人把第一位流出來了,那麼咱們就用128-255的位置好了。
規則
128-159之間爲控制字符,160-255位文字符號,其中包括了西歐語言、希臘語、泰語、阿拉伯語、希伯來語。
恰好把美國人給的空間所有用完,世界真美好,謝謝美利堅預留的每個位置。
磚家們決定把他們的編碼名稱叫作Latin1,後面因爲歐洲統一制定ISO標準,因此又有了一個ISO的名稱,即ISO-8859-1。
實現方式linux

  • 0-127的全部位置不動,那麼能夠兼容ASCII,二進制位0xxx xxxx
  • 128-255位置所有用完,二進制位1xxx xxxx
    因爲全部的位置所有用完,而歐元符號實在指定標準以後纔出現的,因此在這個碼錶中連歐洲人本身的貨幣符號都沒有辦法放進去。

計算機技術固然也傳到了亞洲大地,好比中國。
中國磚家們坐在一塊兒發現,美國人搞的這個東西真的有問題,預留才128-255的空間,但是咱們的漢字個數遠遠超出了這個數目啊,怎麼辦??
後面聰明的中國磚家們發現,只能使用2個字節了,不然真的搞不定。
因爲必須和美國原來制定的ASCII不衝突,因此指定了以下規則
規則windows

  • 若是一個字節中第一位爲0,那麼這就是一個ASCII字符。
  • 若是一個字節中第一位爲1,那麼這個是漢字,認定須要2個字節才表示一個編碼的文字。
    把這個碼錶叫GB2312
    這個碼錶中包含漢字6763個和非漢字圖形字符682個。
    還有不少的空間沒有用到,索性所有預留了吧。
    實現方式
  • 0xxxxxxx:表示爲ASCII字符
    -1xxxxxxx 1xxxxxxx:表示爲漢字

後來,中國磚家們發現,不少的不經常使用漢字沒有在碼錶中,因而添加了不少的漢字進去,這個編碼叫作GBK,實現方式和GB2312是徹底同樣的,兼容GB2312,固然也兼容ASCII。
實現方式服務器

  • 0xxxxxxx:表示爲ASCII字符
    -1xxxxxxx xxxxxxxx:表示爲漢字

後面再次添加更多的字符進去,再次命名爲GB18030,兼容GBK。因爲漢字不少,2個字節並不能徹底包括進去,因此GB18030採用2\4位混編的形式。ide

固然計算機也傳到了日本(JIS)、韓國、臺灣(BIG5)等等地方,你們所有發揮本身的聰明才智,各自實現了本身的編碼。這些編碼都與ASCII兼容,可是相互之間不兼容。ui

使用 2 個字節來表明一個字符的各類漢字延伸編碼方式,稱爲 ANSI 編碼,又稱爲"MBCS(Muilti-Bytes Charecter Set,多字節字符集)"。在簡體中文系統下,ANSI 編碼表明 GB2312 編碼,在日文操做系統下,ANSI 編碼表明 JIS 編碼,因此在中文 windows下要轉碼成gb2312,gbk只須要把文本保存爲ANSI編碼便可。 不一樣ANSI編碼之間互不兼容編碼

第三階段

隨着通信愈來愈多,而老美髮如今本身公司須要國際化的時候,本身原來埋的這個雷真的害了本身。
因而乎,開始研討把世界上幾乎全部文字所有放在一個碼錶中,而這個一應俱全的碼錶就叫作Unicode,即萬國碼。
Unicode是國際組織制定的能夠容納世界上全部文字和符號的字符編碼方案。Unicode用數字0-0x10FFFF來映射這些字符,最多能夠容納1114112個字符,或者說有1114112個碼位。碼位就是能夠分配給字符的數字。
實際上,在軟件製造商的協會(unicode.org)在作這個工做時,國際標準化組織(ISO)在作一樣的事情,最後你們都意識到世界上並不須要兩個不一樣的萬國碼,因而你們坐在一塊兒合併研究的成果,最後的結果就是如今的Unicode。操作系統

各個編碼及其範圍

ASCII

編碼範圍00-7F,其中00-1F、FF爲控制字符。其它爲英文字母、數字、標點符號。.net

Latin1

編碼範圍00-FF,其中00-7F同ASCII,80-9F爲控制符、9F-FF爲字母和標點符號.

CP1252

微軟的企業標準,補充了一些符號和歐元符號,爲Latin1的超集。

GB2312

編碼範圍爲A1A1-F7FE(剔除xx7F),共23940個碼位。其中不少區間沒有用到,而漢字使用的區間爲B0A1-F7FE,其餘爲標點符號和特殊字符。
除經常使用簡體漢字字符外還包括希臘字母、日文平假名及片假名字母、俄語西裏爾字母等字符,未收錄繁體中文漢字和一些生僻字。
對漢字進行了分區管理,其中第一個字節爲區位碼,包括下面區位。
01-09區爲特殊符號。
16-55區爲一級漢字,按拼音排序。
56-87區爲二級漢字,按部首/筆畫排序。
10-15區及88-94區則未有編碼。
第二個字節爲位字節,01-94總計94個。
爲何實際選擇不是01-5E,而是選擇A1-F7的位置呢?
由於英文可見字符區間爲20-7F,加上128(也就是最高位爲1)後獲得的取件便是A1-FE
區位碼使用了0xA1-0xF7(把01-87區的區號加上0xA0),位字節使用了0xA1-0xFE(把01-94加上 0xA0)

GBK

編碼範圍爲8140-FEFE,兼容GB2312,仍然有部分區間沒有用到。
GBK也支持希臘字母、日文假名字母、俄語字母等字符,但不支持韓語中的表音字符(非漢字字符)。GBK還收錄了GB2312不包含的 漢字部首符號、豎排標點符號等字符。

CP936

CP936是微軟指定的標準,屬於企業標準,和GBK的有些許差異,絕大多數狀況下能夠把CP936看成GBK的別名。

BIG5

Big5是雙字節編碼,高字節編碼範圍是0x81-0xFE,低字節編碼範圍是0x40-0x7E和0xA1-0xFE。和GBK相比,少了低字節是0x80-0xA0的組合。0x8140-0xA0FE是保留區域,用於用戶造字區。
Big5收錄的漢字只包括繁體漢字,不包括簡體漢字,一些生僻的漢字也沒有收錄。

CP950

微軟的企業標準,能夠理解爲是對 Big5的擴展。

GB18030

編碼範圍同GBK,補充了更多的字符,因爲Unicode開始流行且GB18030補充的字符都比較生僻,因此實際使用上基本是GBK。
GB18030編碼是變長編碼,有單字節、雙字節和四字節三種方式。GB18030的單字節編碼範圍是0x00-0x7F,徹底等同與ASCII;雙字節編碼的範圍和GBK相同,高字節是0x81-0xFE,低字節的編 碼範圍是0x40-0x7E和0x80-FE;四字節編碼中第1、三字節的編碼範圍是0x81-0xFE,2、四字節是0x30-0x39。

Unicode

中文的編碼範圍爲4E00-9FCF,其中9FC4-9FCF之間的區間沒有使用。
一個蛋疼的問題就是這個區間所有都是文字,中文標點沒有包含在其中,中文標點散落在各個位置。詳細請看http://blog.chinaunix.net/uid-12348673-id-3335307.html。
一些特殊的文字和中文部首以及一些特殊符號也不在此範圍內,詳細狀況能夠參考網址:http://www.cnblogs.com/sosoft/p/3456631.html

編碼方面的一些概念

大尾(big endian)和小尾(little endian)

大尾和小尾是CPU處理多字節數的不一樣方式。例如「漢」字的Unicode編碼是6C49。那麼寫到文件裏時,到底是將6C寫在前面,仍是將49寫在前面?若是將6C寫在前面,就是big endian。仍是將49寫在前面,就是little endian。

BOM

UTF-8以字節爲編碼單元,沒有字節序的問題。UTF-16以兩個字節爲編碼單元,在解釋一個UTF-16文本前,首先要弄清楚每一個編碼單元的字節序。例如收到一個「奎」的Unicode編碼是594E,「乙」的Unicode編碼是4E59。若是咱們收到UTF-16字節流「594E」,那麼這是「奎」仍是「乙」?
Unicode規範中推薦的標記字節順序的方法是BOM,即Byte Order Mark。BOM是一個有點小聰明的想法:
在UCS編碼中有一個叫作"ZERO WIDTH NO-BREAK SPACE"的字符,它的編碼是FEFF。而FFFE在UCS中是不存在的字符,因此不該該出如今實際傳輸中。UCS規範建議咱們在傳輸字節流前,先傳輸字符"ZERO WIDTH NO-BREAK SPACE"。
這樣若是接收者收到FEFF,就代表這個字節流是Big-Endian的;若是收到FFFE,就代表這個字節流是Little-Endian的。所以字符"ZERO WIDTH NO-BREAK SPACE"又被稱做BOM。
UTF-8不須要BOM來代表字節順序,但能夠用BOM來代表編碼方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8編碼是EF BB BF(讀者能夠用咱們前面介紹的編碼方法驗證一下)。因此若是接收者收到以EF BB BF開頭的字節流,就知道這是UTF-8編碼了。

Unicode的實現方式

Unicode只是進行了編碼,也就是說只是一個碼錶,至於具體怎麼實現,並無規定。
下面是Unicode的幾種實現方法。

UTF-8

範圍 字節數 存儲格式
0x0000~0x007F (0 ~ 127) 1字節 0xxxxxxx
0x0080~0x07FF(128 ~ 2047) 2字節 110xxxxx 10xxxxxx
0x0800~FFFF(2048 ~ 65535) 3字節 1110xxxx 10xxxxxx 10xxxxxx
0x10000~1FFFFFF(65536 ~ 2097152) 4字節 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
0x2000000~0x3FFFFFF 5字節 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
0x4000000~0x7FFFFFFF) 6字節 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

理論上說,UTF-8並無大小尾的困擾,因此並不須要BOM。
可是一些Windows應用會指定大小尾,好比Notepad,並且Excel在沒有指定BOM的UTF-8文件進行讀取時會使用Windows的codepage,從而出現錯誤。

UTF-16

在Unicode基本多文種平面定義的字符(不管是拉丁字母、漢字或其餘文字或符號),一概使用2字節儲存。而在輔助平面定義的字符,會以代理對(surrogate pair)的形式,以兩個2字節的值來儲存。
UTF-16比起UTF-8,好處在於大部分字符都以固定長度的字節 (2字節) 儲存,但UTF-16卻沒法兼容於ASCII編碼。
能夠認爲UTF-16是下面介紹的UCS-2的父集。在沒有輔助平面字符(surrogate code points)前,UTF-16與UCS-2所指的是同一的意思。但當引入輔助平面字符後,就稱爲UTF-16了。如今如有軟件聲稱本身支援UCS-2編碼,那實際上是暗指它不能支援在UTF-16中超過2bytes的字集。對於小於0x10000的UCS碼,UTF-16編碼就等於UCS碼。
若是一個UTF-16文件沒有指定BOM,默認應該是UTF-16BE,可是在Intel x86中倒是UTF-16LE。因此在現實世界中有不少的沒有指定大小尾的UTF-16倒是UTF-16LE。

UTF-32

每個Unicode碼位使用剛好32位元。能夠粗暴的認爲UTF-32和下面要介紹的UCS-4是等同的。

UCS-2

採用2個字節,定長的表示每個字符,因此總計能夠表示2^16個字符。

UCS-4

UCS-4根據最高位爲0的最高字節分紅2^7=128個group。每一個group再根據次高字節分爲256個plane。每一個plane根據第3個字節分爲256行(rows),每行包含256個cells。固然同一行的cells只是最後一個字節不一樣,其他都相同。
group 0的plane 0被稱做Basic Multilingual Plane, 即BMP。或者說UCS-4中,高兩個字節爲0的碼位被稱做BMP。
將UCS-4的BMP去掉前面的兩個零字節就獲得了UCS-2。在UCS-2的兩個字節前加上兩個零字節,就獲得了UCS-4的BMP。而目前的UCS-4規範中尚未任何字符被分配在BMP以外。

編碼轉換

請參考
字符編碼之UCS-2與Utf-8
UCS-2和UTF-8的互相轉換

操做系統使用編碼

從Windows2K開始,Win的系統內核開始徹底支持並徹底應用Unicode編寫,全部ANSI字符在進入底層前,都會被相應的API轉換成Unicode。
Linux 服務器上 UCS-2 編碼方式與 Winodws 不一致,如下是有關兩個平臺 UCS-2 編碼的潛規則:

  1. UCS-2 不等於 UTF-16。 UTF-16 每一個字節使用 ASCII 字符範圍編碼,而 UCS-2 對每一個字節的編碼能夠超出 ASCII 字符範圍。UCS-2 和 UTF-16 對每一個字符至多佔兩個字節,可是他們的編碼是不同的。
  2. 對於 UCS-2, windows 下默認是 UCS-2LE。用 MultibyteToWidechar(或者A2W)生成的是 UCS-2LE 的 unicode。windows記事本能夠將文本保存爲 UCS-2BE,至關於多了層轉換。
  3. 對於 UCS-2, linux 下默認是 UCS-2BE。用iconv(指定UCS-2)來轉換生成的是 UCS-2BE 的 unicode。若是轉換windows平臺過來的 UCS-2, 須要指定 UCS-2LE。
  4. 鑑於windows和linux等多個平臺對 UCS-2 的理解不一樣(UCS-2LE,UCS-2BE)。MS 主張 unicode 有個引導標誌(UCS-2LE FFFE, UCS-2BE FEFF),以代表下面的字符是 unicode 而且判別 big-endian 或 little-endian。 因此從 windows 平臺過來的數據發現有這個前綴,不用慌張。

對於JAVA/.NET/Python等這些「新」的語言來講,內置的字符串所使用的字符集已經徹底是Unicode最重要的是,世界上大多數程序用的字符集都是Unicode,由於Unicode有利於程序國際化和標準化。

Python與編碼

我會接着寫另一篇文章。

參考資料

  1. http://blog.chinaunix.net/uid-12348673-id-3335304.html
  2. http://demon.tw/programming/utf-16-ucs-2.html
  3. http://cryolite.iteye.com/blog/505011
  4. http://blog.chinaunix.net/uid-10468429-id-2953054.html
相關文章
相關標籤/搜索