1. 程式人生 > >計算機編碼,unicode、gb等的理解

計算機編碼,unicode、gb等的理解

  • 本文參考:

  https://www.cnblogs.com/gavin-num1/p/5170247.html

  https://blog.csdn.net/iefreer/article/details/4836844

  http://www.fmddlmyy.cn/text6.html

 

  • 前述

  最早接觸的編碼是ASCII,後來常用到的有GB2312、GBK、UTF-8。沒有深入瞭解過各種編碼,糊里糊塗的一直在用UTF-8,每次專案開始啟動的時候會要求專案組成員配置IDE為UTF-8,也還好,基本沒有碰到什麼問題。

  推薦連結,配置IDE編碼為UTF-8:https://www.aliyun.com/jiaocheng/845302.html?spm=5176.100033.2.28.378d18f7wrpYDv

  之前信誓旦旦的說“一個位元組是8位,一個漢字是兩個位元組十六位”,一個位元組8位是對的,但是一個漢字可不一定是兩個位元組。那一個漢字幾個位元組呢?要看哪一種編碼,一般GB系列編碼下是兩個位元組,UTF-8編碼下是三個位元組。可以寫一個簡單的main方法測試一下。

    public static void main(String[] args) throws UnsupportedEncodingException {
        // 測試各種編碼下漢字“一”佔幾個位元組
        System.out.println(new String("").getBytes("
GBK").length); System.out.println(new String("").getBytes("GB2312").length); System.out.println(new String("").getBytes("UTF-8").length); System.out.println(new String("").getBytes("UTF-16").length); System.out.println(new String("").getBytes("UTF-32").length); }

  執行結果:

2
2
3
4
4

   可以看到,GBK、GB2312編碼下漢字“一”佔用2個位元組,UTF-8編碼下佔用3個位元組,UTF-16、UTF-32編碼下佔用4個位元組。所以,在談論一個字元佔用幾個位元組時,不能脫離具體編碼。

  •   組織

  (1) 國際標準化組織(ISO),為各行各業指定標準化規範,其中包括“通用字符集”(Universal Character Set,簡稱UCS),比較出名的是ISO-8859-1
  (2) 統一碼聯盟,制定了一種可以對全球幾乎所有語言文字進行編碼的標準,並且開發了Unicode標準(The Unicode Standard)。

  •   ASCII
/*  
*    
ASCII(American Standard Code for Information Interchange,美國資訊互換標準程式碼,ASCⅡ)是基於拉丁字母的一套電腦編碼系統。
*  它主要用於顯示現代英語和其他西歐語言。它是現今最通用的單位元組編碼系統,並等同於國際標準ISO/IEC 646。 *    ASCII第一次以規範標準的型態發表是在1967年,最後一次更新則是在1986年,至今為止共定義了128個字元,其中33個字元無法顯示(這是以現今
*  作業系統為依歸,但在DOS模式下可顯示出一些諸如笑臉、撲克牌花式等8-bit符號),且這33個字元多數都已是陳廢的控制字元,控制字元的用途主要是
*  用來操控已經處理過的文字,在33個字元之外的是95個可顯示的字元,包含用鍵盤敲下空白鍵所產生的空白字元也算1個可顯示字元(顯示為空白)。
*  引用自: http://ascii.911cha.com/
*/

    1個位元組8位,位有兩種狀態0和1,所以1個位元組能夠有2^8種狀態,也就是256種狀態。從0000000到11111111。

    “上個世紀60年代,美國製定了一套字元編碼,對英語字元與二進位制位之間的關係,做了統一規定。這被稱為ASCII碼,一直沿用至今。

    ASCII碼一共規定了128個字元的編碼,比如空格“SPACE”是32(二進位制00100000),大寫的字母A是65(二進位制01000001)。這128個符號(包括32個不能打印出來的控制符號),只佔用了一個位元組的後面7位,最前面的1位統一規定為0。”

  •       ISO-8859-1
    ISO-8859-1編碼是單位元組編碼,向下相容ASCII,其編碼範圍是0x00-0xFF,0x00-0x7F之間完全和ASCII一致,0x80-0x9F之間是控制字元,0xA0-0xFF之間是文字元號。     很明顯,ISO-8859-1編碼表示的字元範圍很窄,無法表示中文字元。但是,由於是單位元組編碼,和計算機最基礎的表示單位一致,所以很多時候,仍舊使用iso8859-1編碼來表示。而且在很多協議上,預設使用該編碼。比如,雖然"中文"兩個字不存在iso8859-1編碼,以gb2312編碼為例,應該是"d6d0 cec4"兩個字元,使用iso8859-1編碼的時候則將它拆開為4個位元組來表示:"d6 d0 ce c4"(事實上,在進行儲存的時候,也是以位元組為單位處理的)。而如果是UTF編碼,則是6個位元組"e4 b8 ad e6 96 87"。很明顯,這種表示方法還需要以另一種編碼為基礎。
  •      ANSI

    ANSI是預設的編碼方式。對於英文檔案是ASCII編碼,對於簡體中文檔案是GB2312編碼(只針對Windows簡體中文版,如果是繁體中文版會採用Big5碼)。

    ANSI是在ASCII的基礎上的擴充套件。

  •      GB2312/GBK

    這就是漢字的國標碼,專門用來表示漢字,是雙位元組編碼,而英文字母和ISO-8859-1一致(相容ISO-8859-1編碼)。其中GBK編碼能夠用來同時表示繁體字和簡體字,而GB2312只能表示簡體字,GBK是相容GB2312編碼的。

  •      Big5

    又稱為大五碼或五大碼,是使用繁體中文(正體中文)社群中最常用的電腦漢字字符集標準,共收錄13,060個漢字。主要用於臺灣。

  •      UCS/Unicode

    UCS是Unicode的簡稱,根據維基百科全書(http://zh.wikipedia.org/wiki/)的記載:歷史上存在兩個試圖獨立設計Unicode的組織,即國際標準化組織(ISO)和統一碼聯盟。ISO開發了ISO 10646專案,Unicode協會開發了Unicode專案。

    UCS只是規定如何編碼,並沒有規定如何傳輸、儲存這個編碼。例如“漢”字的UCS編碼是6C49,我可以用4個ascii數字來傳輸、儲存這個編碼;也可以用utf-8編碼:3個連續的位元組E6 B1 89來表示它。關鍵在於通訊雙方都要認可。UTF-8、UTF-7、UTF-16都是被廣泛接受的方案。UTF-8的一個特別的好處是它與ISO-8859-1完全相容。UTF是“UCS Transformation Format”的縮寫。

  •      UTF-8

    UTF-8就是以8位為單元對UCS進行編碼。從UCS-2到UTF-8的編碼方式如下:

UCS-2編碼(16進位制) UTF-8 位元組流(二進位制)
0000 - 007F 0xxxxxxx
0080 - 07FF 110xxxxx 10xxxxxx
0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx

    例如“漢”字的Unicode編碼是6C49。6C49在0800-FFFF之間,所以肯定要用3位元組模板了:1110xxxx 10xxxxxx 10xxxxxx。將6C49寫成二進位制是:0110 110001 001001, 用這個位元流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。

    讀者可以用記事本測試一下我們的編碼是否正確。需要注意,UltraEdit在開啟utf-8編碼的文字檔案時會自動轉換為UTF-16,可能產生混淆。你可以在設定中關掉這個選項。更好的工具是Hex Workshop。

    UTF-16以16位為單元對UCS進行編碼。對於小於0x10000的UCS碼,UTF-16編碼就等於UCS碼對應的16位無符號整數。對於不小於0x10000的UCS碼,定義了一個演算法。不過由於實際使用的UCS2,或者UCS4的BMP必然小於0x10000,所以就目前而言,可以認為UTF-16和UCS-2基本相同。但UCS-2只是一個編碼方案,UTF-16卻要用於實際的傳輸,所以就不得不考慮位元組序的問題。

  •      UTF的位元組序和BOM

    UTF-8以位元組為編碼單元,沒有位元組序的問題。UTF-16以兩個位元組為編碼單元,在解釋一個UTF-16文字前,首先要弄清楚每個編碼單元的位元組序。例如“奎”的Unicode編碼是594E,“乙”的Unicode編碼是4E59。如果我們收到UTF-16位元組流“594E”,那麼這是“奎”還是“乙”?

    Unicode規範中推薦的標記位元組順序的方法是BOM。BOM不是“Bill Of Material”的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編碼了。

    Windows就是使用BOM來標記文字檔案的編碼方式的。