ASCII,ISO8859-1,GB2312,GBK,Unicode和字符編碼(UTF-8,UTF-16)的由來和關係

下面介紹幾種常見字符集:

ASCII:


由來:

         在計算機中,所有的數據在存儲和運算時都要使用二進制數表示(因爲計算機用高電平和低電平分別表示1和0),例如,像a、b、c、d這樣的52個字母(包括大寫)、以及0、1等數字還有一些常用的符號(例如*、#、@等)在計算機中存儲時也要使用二進制數來表示,而具體用哪些二進制數字表示哪個符號,當然每個人都可以約定自己的一套,而大家如果要想互相通信而不造成混亂,那麼大家就必須使用相同的編碼規則,於是美國有關的標準化組織就出臺了ASCII編碼,統一規定了上述常用符號用哪些二進制數來表示。

包含哪些字符:

        一共包含128個字符。其中有33個控制字符(不可顯示字符),52個英文字母(包括大小寫),0~9十個阿拉伯數字,其餘爲一些特殊符號。因爲ASCII全稱叫做"American Standard Code for Information Interchange,美國信息交換標準代碼",是用來通信美國字符的,所以不包含中文。

採用哪種(些)字符編碼,它(們)是如何編碼的?

        前面提到過,ASCII字符集在制定的之後也同時指定了編碼的標準,所以它的字符編碼就是ASCII字符編碼。

         ASCII碼使用1個字節的後7位(位,也稱作bit,比特)來表示一個字符,總共表示128個字符(2^7 = 128,二進制編碼爲0000 0000 ~ 0111 1111,對應的十進制就是0~127)。剩下最高位的那一個bit一般爲0,但有時也被用作一些通訊系統的奇偶校驗位。每個字符對應的二進制字節流就是自身在字符集中的字符編號轉換成二進制。比如大寫字母'A'的字符編號是65,所以字母'A'在計算機中就是以'01000001'這樣的二進制字節流存儲的。

每個字符佔幾個字節?

        在ASCII字符集中,每一個字符佔一個字節。



ISO8859-1:


注:圖中的綠色區域並不是沒有定義字符,它們都是不可顯示的控制字符。


由來:

        當計算機開始發展起來的時候,人們逐漸發現,ASCII字符集裏那可憐的128個字符已經不能再滿足他們的需求了。人們就在想一個字節能夠表示的數字(或者說字符編號更準確)有256個,而ASCII字符只用到了0x00~0x7F,也就是佔用了前128個,後面128個數字不用白不用,因此很多人打起了後面這128個數字的主意。可是問題在於,很多人同時有這樣的想法,但是大家對於0x80-0xFF這後面的128個數字分別對應什麼樣的字符,卻有各自的想法。因此出現了很多不同的字符集,比如:ISO8859-1,ISO8859-3等。。。這些字符集的前128個字符都與ASCII中相同,也就是兼容ASCII字符集,但後128位卻各不相同。ISO8859-1就是屬於西歐語系中的一個字符集,比如支持表達阿爾巴尼亞語、巴斯克語、布列塔尼語、加泰羅尼亞語、丹麥語、等,目前使用的最普遍。ISO8859-1有個熟悉的別名:Latin1.

包含哪些字符:

        包含了256個字符。前128個字符與ASCII中完全相同。後128個包括了西歐語言、希臘語、泰語、阿拉伯語、希伯來語對應的文字符號。歐元符號出現的比較晚,沒有被收錄在ISO-8859-1當中。

採用哪種(些)字符編碼,它(們)是如何編碼的?

        同ASCII一樣,也是使用默認的字符編碼。字符編號轉換成二進制後即是字符使用ISO88959-1編碼後在計算機中存儲的形式。

每個字符佔幾個字節?

        在ISO8859-1字符集中,每一個字符佔一個字節。



GB2312:


由來:

        GB2312:中國國家標準簡體中文字符集。當中國人們得到計算機時,已經沒有可以利用的字節狀態來表示漢字,況且有6000多個常用漢字需要保存,於是想到把那些ASCII碼中127號之後的奇異符號們直接取消掉。但這也只能多出來128個字符,離6000還差得遠。所以只好使用兩個字節來表示漢字。所以規定:一個小於127(指一個字節表示的十進制數值)的字節的意義與原來相同,但兩個大於127的字節連在一起時,就表示一個漢字。前面的一個字節(稱之爲高字節)使用0xA1~0xF7這個區間,後面一個字節(低字節)使用0xA1~0xFE這個區間,這樣我們就可以組合出大約7000多個簡體漢字了。

        在這些編碼裏,我們還把數學符號、羅馬希臘的字母、日文的假名們都編進去了,連在 ASCII 裏本來就有的數字、標點、字母都統統重新編了兩個字節長的編碼,這就是常說的"全角"字符,而原來在127號以下的那些就叫"半角"字符了。這種漢字方案叫做 "GB2312"。GB2312 是對 ASCII 的中文擴展。兼容ASCII。GB2312的出現,基本滿足了漢字的計算機處理需要,它所收錄的漢字已經覆蓋中國大陸99.75%的使用頻率。

包含哪些字符:

        GB2312編碼大約包含6000多漢字(不包括特殊字符),編碼範圍爲第一位b0-f7,第二位編碼範圍爲a1-fe(第一位爲cf時,第二位爲a1-d3),計算一下漢字個數爲6762個漢字。當然還有其他的字符。包括控制鍵和其他字符大約7583個字符編碼。

        GB2312對任意一個圖形字符都採用兩個字節表示,並對所收漢字進行了“分區”處理,每區含有 94 個漢字/符號,分別對應第一字節和第二字節。這種表示方式也稱爲區位碼。

(關於區位碼的解釋,請先看"徹底解決亂碼問題(附一)-簡體中文編碼中區位碼、國標碼、內碼、外碼、字形碼的區別及關係",否則對下面GB2312字符編碼的解釋在理解上可能會很困難。)

● 01~09區(682個):特殊符號、數字、英文字符、製表符等,包括拉丁字母、希臘字母、日文平假名及片假名字母、俄語西裏爾字母等在內的682個全角字符;
● 10~15區:空區,留待擴展;
● 16~55區(3755個):常用漢字(也稱一級漢字),按拼音排序;
● 56~87區(3008個):非常用漢字(也稱二級漢字),按部首/筆畫排序;
● 88~94區:空區,留待擴展。

採用哪種(些)字符編碼,它(們)是如何編碼的?

         GB2312採用基於區位碼的字符編碼方案。區位碼其實就是GB2312的字符編號,編碼的方式就是將區碼加上160(20H+80H),轉換爲內碼後,再轉爲二進制就是存儲在計算機中的二進制字節流。詳情見“徹底解決亂碼問題(附一)-簡體中文編碼中區位碼、國標碼、內碼、外碼、字形碼的區別及關係”。

每個字符佔幾個字節?

         漢字,日文等佔兩個字節。英文字母等其他ASCII中的字符依然佔一個字節。因爲計算機會根據高字節的最高位是1和0判斷是中文字符還是英文字符,若是1,則截取兩個字節來解碼。若是0,代表該字符爲英文字符,直接使用ASCII來解碼。



GBK:


由來:

        雖然GB2312基本滿足了我國人在計算機上對漢字的需求。但是中國的漢字太多了,對於人名、古漢語等方面出現的罕用字,GB2312不能處理。不得不繼續把GB2312沒有用到的碼位找出來用上(GB2312編碼中,高字節的編碼範圍是0xA1~0xF7,也就是161~247,而不是128~255,這就造成了浪費)。後來還是不夠用,於是乾脆不再要求低字節一定是127號之後的內碼,只要第一個字節是大於127就固定表示這是一個漢字的開始。這個編碼方案被稱爲 “GBK” 標準,GBK包括了GB2312的所有內容,同時又增加了近20000個新的漢字(包括繁體字)和符號。

        所以GBK是GB2312的擴展,(“K”就是“擴”字拼音的首字母),因此完全兼容GB2312。

包含哪些字符:

        GBK編碼依然採用雙字節編碼方案,其編碼範圍:8140-FEFE,剔除xx7F碼位,共23940個碼位。共收錄漢字和圖形符號21886個,其中漢字(包括部首和構件)21003個,圖形符號883個。
    全部編碼分爲三大部分:
1. 漢字區。包括:
a. GB2312 漢字區。即 GBK/2: B0A1-F7FE。收錄 GB 2312 漢字 6763 個,按原順序排列。
b. GB 13000.1 擴充漢字區。包括:
    (1) GBK/3: 8140-A0FE。收錄 GB 13000.1 中的 CJK 漢字 6080 個。
    (2) GBK/4: AA40-FEA0。收錄 CJK 漢字和增補的漢字 8160 個。CJK 漢字在前,按 UCS 代碼大小排列;增補的漢字(包括部首和構件)在後,按《康熙字典》的頁碼/字位排列。

    (3) 漢字“〇”安排在圖形符號區GBK/5:A996。

2. 圖形符號區。包括:
a. GB2312 非漢字符號區。即GBK/1: A1A1-A9FE。其中除GB2312的符號外,還有10個小寫羅馬數字和GB12345增補的符號。計符號 717 個。

b. GB13000.1擴充非漢字區。即GBK/5: A840-A9A0。BIG-5 非漢字符號、結構符和“〇”排列在此區。計符號 166 個。

3. 用戶自定義區:分爲(1)(2)(3)三個小區。
(1) AAA1-AFFE,碼位 564 個。
(2) F8A1-FEFE,碼位 658 個。
(3) A140-A7A0,碼位 672 個。

第(3)區儘管對用戶開放,但限制使用,因爲不排除未來在此區域增補新字符的可能性。

採用哪種(些)字符編碼,它(們)是如何編碼的?

        GBK雖然是GB2312的擴展,但他的編碼方式已經不再基於區位碼。從哪裏看出來的呢?

        如果留意過早些年的手機(功能機),會發現人名中常見的“燊”字是打不出來的。爲什麼呢?因爲早期的區位碼錶裏面並沒有這些字,也就是說早期的GB2312也是沒有這些字的。到後來的GBK才補充了大量的漢字進去,當然現在的安卓蘋果應該都是GBK字庫了。再看看這些補充的漢字的字節碼(也就是內碼),如“燊”字在GBK中的編碼是0x9F 0xF6。

        和前面說到的GB2312不同,有的字的編碼比0xA0 0xA0(轉換爲區位碼是0 0,也就是區位碼錶的開頭)還小,難道新補充的區位號還能是負的??其實不然,這次的補充只補充了計算機編碼表,並沒有補充區位碼錶。也就是說區位碼錶並沒有更新,用區位碼還是打不出這些字,而網上的反向區位碼錶查詢也只是按照GBK的編碼計算,並不代表字與區位號完全對應。時代的發展,區位碼錶早已經是進入博物館的東西了。

        所以GBK字符集對應的就是GBK字符編碼。編碼方式同上述的字符集一樣,通過簡單的查表(字符-字節映射)即可完成。

每個字符佔幾個字節?

        同GB2312一樣。




Unicode:


由來:

        隨着計算機發展到世界各地,於是各個國家和地區各自爲政,搞出了很多既兼容ASCII但又互相不兼容的各種編碼方案。這樣一來同一個二進制編碼就有可能被解釋成不同的字符,導致不同的字符集在交換數據時帶來極大的不便。

想象一下,如果有一種統一的字符集,將世界上所有語言字符都納入其中,每一個字符都給予一個全球獨一無二的編碼,那麼亂碼問題就會消失。於是,全球所有國家和民族使用的所有語言字符的統一字符集誕生了,這就是Unicode字符集。Unicode的名字起的很形象:該字符集是爲了給全世界所有字符一個唯一的編碼,“唯一”對應的英文爲Unique,而編碼的英文爲code,兩者結合一下就產生了Unicode。平常見到的“U+0024”這樣的數值,就代表Unicode字符集中的一個字符編號。

想象一下,如果有一種統一的字符集,將世界上所有語言字符都納入其中,每一個字符都給予一個全球獨一無二的編碼,那麼亂碼問題就會消失。於是,全球所有國家和民族使用的所有語言字符的統一字符集誕生了,這就是Unicode字符集。Unicode的名字起的很形象:該字符集是爲了給全世界所有字符一個唯一的編碼,“唯一”對應的英文爲Unique,而編碼的英文爲code,兩者結合一下就產生了Unicode。平常見到的“U+0024”這樣的數值,就代表Unicode字符集中的一個字符編號。

包含了哪些字符?

        All of The Character。全世界所有存在的字符都被包括在內。是所有!所有!

採用哪種(些)字符編碼,它(們)是如何編碼的?

        首先聲明,Unicode的產生象徵着字符編碼領域進入了一個新時代。爲什麼這麼說呢?在Unicode之前所有制定的字符集都沒有考慮到擴展性,所有的字符集都是和具體編碼方案綁定在一起的(比如:GB2312,GBK,等,除了有“字符的集合”這層含義外,同時也包含了“編碼”的含義.),都是直接將字符和最終字節流綁定死了,例如ASCII編碼系統規定使用7比特來編碼ASCII字符集,直接使用字符編號的二進制作爲二進制字節流;GB2312基於區位碼來編碼,它和GBK字符集都限定了使用最多2個字節來編碼所有字符,並且規定了字節序(不要求理解)。這樣的編碼系統通常用簡單的查表,也就是通過代碼頁就可以直接將字符映射爲存儲設備上的字節流了。例如下面這個例子:


        這種方式的缺點在於,字符和字節流之間耦合得太緊密了,從而限定了字符集的擴展能力。假設以後火星人入住地球了,要往現有字符集中加入火星文就變得很難甚至不可能了,而且很容易破壞現有的編碼規則。

因此Unicode在設計上考慮到了這一點,將字符集和字符編碼方案分離開。


        也就是說,雖然每個字符在Unicode字符集中都能找到唯一確定的編號(字符碼,又稱Unicode碼),但是決定最終字節流的卻是具體的字符編碼。例如同樣是對Unicode字符“A”進行編碼,UTF-8字符編碼得到的字節流是0x41,而UTF-16(大端模式)得到的是0x00 0x41。

因此上篇博客中說,在Unicode誕生之前可以將字符集和字符編碼混爲一談,而在Unicode中必須嚴格區分開。例如可以說“採用GBK字符集或字符編碼”,而不能說使用“UTF-8字符集”。

UTF-8、UTF-16等,它們只是Unicode字符集中所採用的具體的字符編碼。這個概念要先搞清楚。

Unicode字符集採用了許多種字符編碼方式。比如“UTF-8”,“UTF-16”,“UTF-32”等, 下文只着重介紹常用的“UTF-8”,“UTF-16”的介紹請看別的文章。

UTF-8:

        UTF-8是一個非常驚豔的概念,它完美實現了對ASCII碼的向後兼容,以保證Unicode可以被大衆接受。在UTF-8中,0-127號的字符用1個字節來表示,使用和ASCII相同的編碼。這意味着1980年代寫的文檔用UTF-8打開一點問題都沒有。只有128號及以上的字符才用2個,3個或者4個字節來表示。因此,UTF-8被稱作可變長度編碼。下面講解一下UTF-8的編碼方式。

前面說過,字符集其實是“編號字符集”,而字符編碼是定義了字符編號到實際存儲的二進制字節流的映射,所以我會根據下表來分析UTF-8是如何實現字符編號到字節流的映射並做到映射出的字節流長度可變。


        這個表格抽象的說明了,被UTF-8編碼後得出的字節流的特徵。其中x代表序號部分,把各個字節中的所有x部分拼接在一起就組成了在Unicode字符集中的字符編號:

     如果一個字節的第一位爲0,那麼代表當前字符爲單字節字符,佔用1個字節的空間。0之後的所有部分(7個bit)代表在Unicode中的字符編號。

                ● 如果一個字節以110開頭,那麼代表當前字符爲雙字節字符,佔用2個字節的空間。110之後的所有部分(5個bit)加上後一個字節的除10外的部分(6個bit)代表在Unicode中的字符編號。且第二個字節以10開頭

如果一個字節以1110開頭,那麼代表當前字符爲三字節字符,佔用3個字節的空間。1110之後的所有部分(4個bit)加上後兩個字節的除10外的部分(12個bit)代表在Unicode中的字符編號。且第二、第三個字節以10開頭

如果一個字節以11110開頭,那麼代表當前字符爲四字節字符,佔用4個字節的空間。11110之後的所有部分(3個bit)加上後三個字節的除10外的部分(18個bit)代表在Unicode中的字符編號。且第二、第三、第四個字節以10開頭

        舉個實例:

   

UTF-16:

        請看這篇文章



上一張圖總結一下吧。


        希望通過這篇博客,大家能夠區分開字符集和字符編碼,並對常用的字符集和字符編碼有自己的理解。100個人看,10個人贊,1個人懂我就很滿足了。

[原文地址](https://blog.csdn.net/wn084/article/details/80363792)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章