天天看點

編碼字元集

在計算機中,隻有二進制的資料,不管資料是在記憶體中,還是在外部儲存設備上。對于我們所看到的字元,也是以二進制資料的形式存在的。不同字元對應二進制數的規則,就是字元的編碼。字元編碼的集合稱為字元集。

****常用******字元集**

在早期的計算機系統中,使用的字元非常少,這些字元包括26個英文字母、數字元号和一些常用符号(包括控制符号),對這些字元進行編碼,用1個位元組就足夠了(1個位元組可以表示28=256種字元)。然而實際上,表示這些字元,隻使用了1個位元組的7位,這就是ASCII編碼。

*1.ASCII*

ASCII(American Standard Code for Information Interchange,美國資訊互換标準代碼),是基于常用的英文字元的一套電腦編碼系統。每一個**ASCII碼**與一個8位(bit)二進制數對應。其最高位是0,相應的十進制數是0~127。例如,數字字元“0”的編碼用十進制數表示就是48。另有128個擴充的ASCII碼,最高位都是1,由一些圖形和畫線符号組成。ASCII是現今最通用的單位元組編碼系統。

ASCII用一個位元組來表示字元,最多能夠表示256種字元。随着計算機的普及,許多國家都将本地的語言符号引入到計算機中,擴充了計算機中字元的範圍,于是就出現了各種不同的字元集。

*2.ISO8859-1*

因為ASCII碼中缺少****£、ü和許多書寫其他語言所需的字元****,為此,可以通過指定128以後的字元來擴充ASCII碼。國際标準組織(ISO)定義了幾個不同的字元集,它們是在ASCII碼基礎上增加了其他語言和地區需要的字元。其中最常用的是ISO8859-1,通常叫做Latin-1。Latin-1包括了書寫所有西方歐洲語言不可缺少的附加字元,其中0~127的字元與ASCII碼相同。ISO 8859另外定義了14個适用于不同文字的字元集(8859-2到8859-15)。這些字元集共享0~127的ASCII碼,隻是每個字元集都包含了128~255的其他字元。

*3.GB2312和GBK*

GB2312是中華人民共和國國家标準漢字資訊交換用編碼,全稱《資訊交換用漢字編碼字元集-基本集》,标準号為GB2312-80,是一個由中華人民共和國國家标準總局釋出的關于簡化漢字的編碼,通行于中國大陸和新加坡,簡稱國标碼。

因為中文字元數量較多,是以采用兩個位元組來表示一個字元,分别稱為高位和低位。為了和ASCII碼有所差別,中文字元的每一個位元組的最高位都用1來表示。GB2312字元集是幾乎所有的中文系統和國際化的軟體都支援的中文字元集,也是最基本的中文字元集。它包含了大部分常用的一、二級漢字和9區的符号,其編碼範圍是高位0xa1-0xfe,低位也是0xa1-0xfe,漢字從0xb0a1開始,結束于0xf 7fe。

為了對更多的字元和符号進行編碼,由前電子部科技品質司和國家技術監督局标準化司于1995年12月頒布了GBK(K是“擴充”的漢語拼音第一個字母)編碼規範,在新的編碼系統裡,除了完全相容GB2312外,還對繁體中文、一些不常用的漢字和許多符号進行了編碼。

*GBK********

***也是現階段Windows和其他一些中文作業系統的預設字元集,但并不是所有的國際化軟體都支援該字元集。****不過要注意的是GBK不是國家标準,它隻是規範。GBK字元集包含了20 902個漢字,其編碼範圍是0x8140-0xfefe。

每個國家(或區域)都規定了計算機資訊交換用的字元編碼集,這就造成了交流上的困難。想像一下,你發送一封中文郵件給一位遠在西班牙的朋友,當郵件通過網絡發送出去的時候,你所書寫的中文字元會按照本地的字元集GBK轉換為二進制編碼資料,然後發送出去。當你的朋友接收到郵件(二進制資料)後,檢視信件時,會按照他所用系統的字元集,将二進制編碼資料解碼為字元,然而由于兩種字元集之間編碼的規則不同,導緻轉換出現亂碼。這是因為,在不同的字元集之間,同樣的數字可能對應了不同的符号,也可能在另一種字元集中,該數字沒有對應符号。

*為了解決上述問題,統一全世界的字元編碼,由Unicode協會制定并釋出了Unicode編碼。*

*4.Unicode*

Unicode(統一的字元編碼标準集)使用0~65 535的雙位元組無符号數對每一個字元進行編碼。它不僅包含來自英語和其他西歐國家字母表中的常見字母和符号,也包含來自古斯拉夫語、希臘語、希伯來語、阿拉伯語和梵語的字母表。另外還包含漢語和日語的象形漢字和南韓的Hangul音節表。

目前已經定義了40 000多個不同的Unicode字元,剩餘25 000個空缺留給将來擴充使用。其中大約20 000個字元用于漢字,另外11 000左右的字元用于韓語音節。Unicode中0~255的字元與ISO8859-1中的一緻。

Unicode編碼對于英文字元采取前面加“0”位元組的政策實作等長相容。如“a”的ASCII碼為0x61,Unicode碼就為0x00,0x61。

****5.******UTF-8**

使用Unicode編碼,一個英文字元要占用兩個位元組,在Internet上,大多數的資訊都是用英文來表示的,如果都采用Unicode編碼,将會使資料量增加一倍。為了減少存儲和傳輸英文字元資料的資料量,可以使用UTF-8編碼。

UTF-8全稱是Eight-bit UCS Transformation Format(UCS,Universal Character Set,通用字元集,UCS是所有其他字元集标準的一個超集)。對于常用的字元,即0~127的ASCII字元,UTF-8用一個位元組來表示,這意味着隻包含7位ASCII字元的字元資料在ASCII和UTF-8兩種編碼方式下是一樣的。如果字元對應的Unicode碼是0x0000,或在0x0080與0x007f之間,對應的UTF-8編碼是兩個位元組,如果字元對應的Unicode碼在0x0800與0xffff之間,對應的UTF-8編碼是三個位元組。因為中文字元的Unicode編碼在0x0800與0xffff之間,是以資料如果是中文,采用UTF-8編碼資料量會增加50%。

Unicode與UTF-8轉換的規則簡述如下:

(1)如果Unicode編碼的16位二進制數的前9位是0,則UTF-8編碼用1個位元組來表示,這個位元組的首位是“0”,剩下的7位與原二進制資料的後7位相同。例如:

Unicode編碼:\u0061 = 00000000 01100001

UTF-8編碼:01100001 = 0x61

(2)如果Unicode編碼的16位二進制數的頭5位是0,則UTF-8編碼用2個位元組來表示,首位元組以“110”開頭,後面的5位與原二進制資料除去前5個零後的最高5位相同;第二個位元組以“10”開頭,後面的6位與原二進制資料中的低6位相同。例如:

Unicode編碼:\u00A9 = 00000000 10101001

UTF-8編碼:11000010 10101001 = 0xC2 0xA9

(3)如果不符合上述兩個規則,則用三個位元組表示。第一個位元組以“1110”開頭,後四位為原二進制資料的高四位;第二個位元組以“10”開頭,後六位為原二進制資料中間的六位;第三個位元組以“10”開頭,後六位為原二進制資料的低六位。例如:

Unicode編碼:\u4E2D = 01001110 00101101

UTF-8編碼:11100100 10111000 10101101 = 0xE4 0xB8 0xAD

在UTF-8編碼的多位元組串中,第一個位元組開頭“1”的數目就是整個字元串中位元組的數目。

*對亂碼産生過程的分析*

為了讓使用**Java語言**編寫的程式能在各種語言的平台下運作,Java在其内部****使用Unicode字元集來表示字元****,這樣就****存在Unicode字元集和本地字元集進行轉換的過程****。當在Java中讀取字元資料的時候,需要将本地字元集編碼的資料轉換為Unicode編碼,而在輸出字元資料的時候,則需要将Unicode編碼轉換為本地字元集編碼。

例如,在中文系統下,從控制台讀取一個字元“中”,實際上讀取的是“中”的GBK編碼0xD6D0,在Java語言中要将GBK編碼轉換為Unicode編碼0x4E2D,此時,在記憶體中,字元“中”對應的數值就是0x4E2D,當我們向控制台輸出字元時,Java語言将Unicode編碼再轉換為GBK編碼,輸出到控制台,中文系統再根據GBK字元集畫出相應的字元。

從上述過程來看,讀取和寫入的過程是可逆的,那麼理應不會出現中文亂碼問題。然而,實際應用的情形,比上述過程要複雜得多。在Web應用中,通常都包括了浏覽器、Web伺服器、Web應用程式和資料庫等部分,每一部分都有可能使用不同的字元集,進而導緻字元資料在各種不同的字元集之間轉換時,出現亂碼的問題。

繼續閱讀