天天看點

ASCII碼、Unicode(統編)、UTF-8、GB國标碼的比較

1. ASCII碼

我們知道,在計算機内部,所有的資訊最終都表示為一個二進制的字元串。每一個二進制位(bit)有0和 1兩種狀态,是以八個二進制位就可以組合出256種狀态,這被稱為一個位元組(byte)。也就是說,一個位元組一共可以用來表示256種不同的狀态,每一個狀态對應一個符号,就是256個符号,從0000000到11111111。

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

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

2、非ASCII編碼

英語用128個符号編碼就夠了,但是用來表示其他語言,128個符号是不夠的。比如,在法語中,字母上方有注音符号,它就無法用ASCII碼表示。于是,一些歐洲國家就決定,利用位元組中閑置的最高位編入新的符号。比如,法語中的é的編碼為130(二進制 10000010)。這樣一來,這些歐洲國家使用的編碼體系,可以表示最多256個符号。

但是,這裡又出現了新的問題。不同的國家有不同的字母,是以,哪怕它們都使用256個符号的編碼方式,代表的字母卻不一樣。比如,130在法語編碼中代表了é,在希伯來語編碼中卻代表了字母Gimel (),在俄語編碼中又會代表另一個符号。但是不管怎樣,所有這些編碼方式中,0—127表示的符号是一樣的,不一樣的隻是128—255的這一段。

至于亞洲國家的文字,使用的符号就更多了,漢字就多達10萬左右。一個位元組隻能表示256種符号,肯定是不夠的,就必須使用多個位元組表達一個符号。比如,簡體中文常見的編碼方式是GB2312,使用兩個位元組表示一個漢字,是以理論上最多可以表示 256x256=65536個符号。

中文編碼的問題需要專文讨論,這篇筆記不涉及。這裡隻指出,雖然都是用多個位元組表示一個符号,但是GB類的漢字編碼與後文的Unicode和UTF-8是毫無關系的。

3、Unicode

Unicode字元集(簡稱為UCS),國際标準組織于1984年4月成立ISO/IEC JTC1/SC2/WG2工作組,針對各國文字、符号進行統一性編碼。1991年美國跨國公司成立Unicode Consortium,并于1991年10月與WG2達成協定,采用同一編碼字集。目前Unicode是采用16位編碼體系,其字元集内容與 ISO10646的BMP(Basic Multilingual Plane)相同。Unicode于1992年6月通過DIS(Draf International Standard),目前版本V2.0于1996公布,内容包含符号6811個,漢字20902個,韓文拼音11172個,造字區6400個,保留 20249個,共計65534個。Unicode編碼後的大小是一樣的.例如一個英文字母 "a" 和 一個漢字 "好",編碼後都是占用的空間大小是一樣的,都是兩個位元組!

Unicode可以用來表示所有語言的字元,而且是定長雙位元組(也有四位元組的)編碼,包括英文字母在内。是以可以說它是不相容iso8859-1編碼的,也不相容任何編碼。不過,相對于iso8859-1編碼來說,uniocode編碼隻是在前面增加了一個0位元組,比如字母'a'為"00 61"。

需要說明的是,定長編碼便于計算機處理(注意GB2312/GBK不是定長編碼),而unicode又可以用來表示所有字元,是以在很多軟體内部是使用unicode編碼來處理的,比如java。

Unicode當然是一個很大的集合,現在的規模可以容納100多萬個符号。每個符号的編碼都不一樣,比如,U+0639表示阿拉伯字母Ain,U+0041表示英語的大寫字母A,U+4E25表示漢字“嚴”。具體的符号對應表,可以查詢 unicode.org,或者專門的漢字對應表。 http://www.chi2ko.com/tool/CJK.htm

4. Unicode的問題

需要注意的是,Unicode隻是一個符号集,它隻規定了符号的二進制代碼,卻沒有規定這個二進制代碼應該如何存儲。

比如,漢字“嚴”的unicode是十六進制數4E25,轉換成二進制數足足有15位(100111000100101),也就是說這個符号的表示至少需要2個位元組。表示其他更大的符号,可能需要3個位元組或者4個位元組,甚至更多。

這裡就有兩個嚴重的問題,第一個問題是,如何才能差別unicode和ascii?計算機怎麼知道三個位元組表示一個符号,而不是分别表示三個符号呢?第二個問題是,我們已經知道,英文字母隻用一個位元組表示就夠了,如果unicode統一規定,每個符号用三個或四個位元組表示,那麼每個英文字母前都必然有二到三個位元組是0,這對于存儲來說是極大的浪費,文本檔案的大小會是以大出二三倍,這是無法接受的。

它們造成的結果是:1)出現了unicode的多種存儲方式,也就是說有許多種不同的二進制格式,可以用來表示unicode。2)unicode在很長一段時間内無法推廣,直到網際網路的出現。

5.UTF-8 網際網路的普及,強烈要求出現一種統一的編碼方式。UTF-8就是在網際網路上使用最廣的一種unicode的實作方式。其他實作方式還包括UTF-16和UTF-32,不過在網際網路上基本不用。重複一遍,這裡的關系是,UTF-8是Unicode的實作方式之一。

UTF-8最大的一個特點,就是它是一種變長的編碼方式。它可以使用1~4個位元組表示一個符号,根據不同的符号而變化位元組長度。

UTF-8的編碼規則很簡單,隻有二條: 1)對于單位元組的符号,位元組的第一位設為0,後面7位為這個符号的unicode碼。是以對于英語字母,UTF-8編碼和ASCII碼是相同的。 2)對于n位元組的符号(n>1),第一個位元組的前n位都設為1,第n+1位設為0,後面位元組的前兩位一律設為10。剩下的沒有提及的二進制位,全部為這個符号的unicode碼。

下表總結了編碼規則,字母x表示可用編碼的位。 Unicode符号範圍 | UTF-8編碼方式

(十六進制) | (二進制)

--------------------+---------------------------------------------

0000 0000-0000 007F | 0xxxxxxx

0000 0080-0000 07FF | 110xxxxx 10xxxxxx

0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx

0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

下面,還是以漢字“嚴”為例,示範如何實作UTF-8編碼。 已知“嚴”的unicode是4E25(100111000100101),根據上表,可以發現 4E25處在第三行的範圍内(0000 0800-0000 FFFF),是以“嚴”的UTF-8編碼需要三個位元組,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。然後,從“嚴”的最後一個二進制位開始,依次從後向前填入格式中的x,多出的位補0。這樣就得到了,“嚴”的UTF-8編碼是 “11100100 10111000 10100101”,轉換成十六進制就是E4B8A5。

6. Unicode與UTF-8之間的轉換

通過上一節的例子,可以看到“嚴”的Unicode碼是4E25,UTF-8編碼是E4B8A5,兩者是不一樣的。它們之間的轉換可以通過程式實作。

在Windows平台下,有一個最簡單的轉化方法,就是使用内置的記事本小程式Notepad.exe。打開檔案後,點選“檔案”菜單中的“另存為”指令,會跳出一個對話框,在最底部有一個“編碼”的下拉條。   裡面有四個選項:ANSI,Unicode,Unicode big endian 和 UTF-8。 1)ANSI是預設的編碼方式。對于英文檔案是ASCII編碼,對于簡體中文檔案是GB2312編碼(隻針對Windows簡體中文版,如果是繁體中文版會采用Big5碼)。 2)Unicode編碼指的是UCS-2編碼方式,即直接用兩個位元組存入字元的Unicode碼。這個選項用的little endian格式。 3)Unicode big endian編碼與上一個選項相對應。我在下一節會解釋little endian和big endian的涵義。 4)UTF-8編碼,也就是上一節談到的編碼方法。

選擇完”編碼方式“後,點選”儲存“按鈕,檔案的編碼方式就立刻轉換好了。

7. Little endian和Big endian

上一節已經提到,Unicode碼可以采用UCS-2格式直接存儲。以漢字”嚴“為例,Unicode 碼是4E25,需要用兩個位元組存儲,一個位元組是4E,另一個位元組是25。存儲的時候,4E在前,25在後,就是Big endian方式;25在前,4E在後,就是Little endian方式。

這兩個古怪的名稱來自英國作家斯威夫特的《格列佛遊記》。在該書中,小人國裡爆發了内戰,戰争起因是人們争論,吃雞蛋時究竟是從大頭(Big-Endian)敲開還是從小頭(Little-Endian)敲開。為了這件事情,前後爆發了六次戰争,一個皇帝送了命,另一個皇帝丢了王位。

是以,第一個位元組在前,就是”大頭方式“(Big endian),第二個位元組在前就是”小頭方式“(Little endian)。

那麼很自然的,就會出現一個問題:計算機怎麼知道某一個檔案到底采用哪一種方式編碼?

Unicode規範中定義,每一個檔案的最前面分别加入一個表示編碼順序的字元,這個字元的名字叫做”零寬度非換行空格“(ZERO WIDTH NO-BREAK SPACE),用FEFF表示。這正好是兩個位元組,而且FF比FE大1。

如果一個文本檔案的頭兩個位元組是FE FF,就表示該檔案采用大頭方式;如果頭兩個位元組是FF FE,就表示該檔案采用小頭方式。

8. 執行個體

下面,舉一個執行個體。

打開”記事本“程式Notepad.exe,建立一個文本檔案,内容就是一個”嚴“字,依次采用ANSI,Unicode,Unicode big endian 和 UTF-8編碼方式儲存。

然後,用文本編輯軟體UltraEdit中的”十六進制功能“,觀察該檔案的内部編碼方式。

1)ANSI:檔案的編碼就是兩個位元組“D1 CF”,這正是“嚴”的GB2312編碼,這也暗示GB2312是采用大頭方式存儲的。 2)Unicode:編碼是四個位元組“FF FE 25 4E”,其中“FF FE”表明是小頭方式存儲,真正的編碼是4E25。 3)Unicode big endian:編碼是四個位元組“FE FF 4E 25”,其中“FE FF”表明是大頭方式存儲。 4)UTF-8:編碼是六個位元組“EF BB BF E4 B8 A5”,前三個位元組“EF BB BF”表示這是UTF-8編碼,後三個“E4B8A5”就是“嚴”的具體編碼,它的存儲順序與編碼順序是一緻的。

9 國标

9.1 GB碼     全稱是GB2312-80《資訊交換用漢字編碼字元集基本集》,1980年釋出,是中文資訊處理的國家标準,在大陸及海外使用簡體中文的地區(如新加坡等)是強制使用的唯一中文編碼。P-Windows3.2和蘋果OS就是以GB2312為基本漢字編碼, Windows 95/98則以GBK為基本漢字編碼、但相容支援GB2312。

雙位元組編碼

範圍:A1A1~FEFE

A1-A9:符号區,包含682個符号

B0-F7:漢字區,包含6763個漢字   9.2 GB2312     GB2312(1980年)一共收錄了7445個字元,包括6763個漢字和682個其它符号。漢字區的内碼範圍高位元組從B0-F7,低位元組從 A1-FE,占用的碼位是72*94=6768。其中有5個空位是D7FA-D7FE。GB2312-80中共收錄了7545個字元,用兩個位元組編碼一個字元。每個字元最高位為0。GB2312-80編碼簡稱國标碼。   GB2312支援的漢字太少。1995年的漢字擴充規範GBK1.0收錄了21886個符号,它分為漢字區和圖形符号區。漢字區包括21003個字元。   9.3 GB12345-90 1990年制定了繁體字的編碼标準GB12345-90《資訊交換用漢字編碼字元集第一輔助集》,目的在于規範必須使用繁體字的各種場合,以及古籍整理等。該标準共收錄6866個漢字(比GB2312多103個字,其它廠商的字庫大多不包括這些字),純繁體的字大概有2200餘個。

雙位元組編碼

範圍:A1A1~FEFE

A1-A9:符号區,增加豎排符号

B0-F9:漢字區,包含6866個漢字   9.4 GBK     GBK編碼(Chinese Internal Code Specification)是中國大陸制訂的、等同于UCS的新的中文編碼擴充國家标準。gbk編碼能夠用來同時表示繁體字和簡體字,而gb2312隻能表示簡體字,gbk是相容gb2312編碼的。GBK工作小組于1995年10月,同年12月完成GBK規範。該編碼标準相容GB2312,共收錄漢字 21003個、符号883個,并提供1894個造字碼位,簡、繁體字融于一庫。Windows95/98簡體中文版的字庫表層編碼就采用的是GBK,通過 GBK與UCS之間一一對應的碼表與底層字庫聯系。

英文名:Chinese Internal Code Specification

中文名:漢字内碼擴充規範1.0版

雙位元組編碼,GB2312-80的擴充,在碼位上和GB2312-80相容

範圍:8140~FEFE(剔除xx7F)共23940個碼位

包含21003個漢字,包含了ISO/IEC 10646-1中的全部中日韓漢字     一、什麼是字元集?什麼是編碼? 字元(Character)是文字與符号的總稱,包括文字、圖形符号、數學符号等。

一組抽象字元的集合就是字元集(Charset)。

字元集常常和一種具體的語言文字對應起來,該文字中的所有字元或者大部分常用字元就構成了該文字的字元集,比如英文字元集。

一組有共同特征的字元也可以組成字元集,比如繁體漢字字元集、日文漢字字元集。

字元集的子集也是字元集。 計算機要處理各種字元,就需要将字元和二進制内碼對應起來,這種對應關系就是字元編碼(Encoding)。

制定編碼首先要确定字元集,并将字元集内的字元排序,然後和二進制數字對應起來。根據字元集内字元的多少,會确定用幾個位元組來編碼。

每種編碼都限定了一個明确的字元集合,叫做被編碼過的字元集(Coded Character Set),這是字元集的另外一個含義。通常所說的字元集大多是這個含義。 二、有哪些字元集? ASCII:

American Standard Code for Information Interchange,美國資訊交換标準碼。

目前計算機中用得最廣泛的字元集及其編碼,由美國國家标準局(ANSI)制定。

它已被國際标準化組織(ISO)定為國際标準,稱為ISO 646标準。

ASCII字元集由控制字元和圖形字元組成。

在計算機的存儲單元中,一個ASCII碼值占一個位元組(8個二進制位),其最高位(b7)用作奇偶校驗位。

所謂奇偶校驗,是指在代碼傳送過程中用來檢驗是否出現錯誤的一種方法,一般分奇校驗和偶校驗兩種。

奇校驗規定:正确的代碼一個位元組中1的個數必須是奇數,若非奇數,則在最高位b7添1。

偶校驗規定:正确的代碼一個位元組中1的個數必須是偶數,若非偶數,則在最高位b7添1。 ISO 8859-1:

ISO 8859,全稱ISO/IEC 8859,是國際标準化組織(ISO)及國際電工委員會(IEC)聯合制定的一系列8位字元集的标準,現時定義了15個字元集。

ASCII收錄了空格及94個“可印刷字元”,足以給英語使用。

但是,其他使用拉丁字母的語言(主要是歐洲國家的語言),都有一定數量的變音字母,故可以使用ASCII及控制字元以外的區域來儲存及表示。

除了使用拉丁字母的語言外,使用西裡爾字母的東歐語言、希臘語、泰語、現代阿拉伯語、希伯來語等,都可以使用這個形式來儲存及表示。

    * ISO 8859-1 (Latin-1) - 西歐語言

    * ISO 8859-2 (Latin-2) - 中歐語言

    * ISO 8859-3 (Latin-3) - 南歐語言。世界語也可用此字元集顯示。

    * ISO 8859-4 (Latin-4) - 北歐語言

    * ISO 8859-5 (Cyrillic) - 斯拉夫語言

    * ISO 8859-6 (Arabic) - 阿拉伯語

    * ISO 8859-7 (Greek) - 希臘語

    * ISO 8859-8 (Hebrew) - 希伯來語(視覺順序)

    * ISO 8859-8-I - 希伯來語(邏輯順序)

    * ISO 8859-9 (Latin-5 或 Turkish) - 它把Latin-1的冰島語字母換走,加入土耳其語字母。

    * ISO 8859-10 (Latin-6 或 Nordic) - 北日耳曼語支,用來代替Latin-4。

    * ISO 8859-11 (Thai) - 泰語,從泰國的 TIS620 标準字集演化而來。

    * ISO 8859-13 (Latin-7 或 Baltic Rim) - 波羅的語族

    * ISO 8859-14 (Latin-8 或 Celtic) - 凱爾特語族

    * ISO 8859-15 (Latin-9) - 西歐語言,加入Latin-1欠缺的法語及芬蘭語重音字母,以及歐元符号。

    * ISO 8859-16 (Latin-10) - 東南歐語言。主要供羅馬尼亞語使用,并加入歐元符号。

很明顯,iso8859-1編碼表示的字元範圍很窄,無法表示中文字元。

但是,由于是單位元組編碼,和計算機最基礎的表示機關一緻,是以很多時候,仍舊使用iso8859-1編碼來表示。

而且在很多協定上,預設使用該編碼。 UCS:

通用字元集(Universal Character Set,UCS)是由ISO制定的ISO 10646(或稱ISO/IEC 10646)标準所定義的字元編碼方式,采用4位元組編碼。

UCS包含了已知語言的所有字元。

除了拉丁語、希臘語、斯拉夫語、希伯來語、阿拉伯語、亞美尼亞語、格魯吉亞語,還包括中文、日文、韓文這樣的象形文字,UCS還包括大量的圖形、印刷、數學、科學符号。

    * UCS-2: 與unicode的2byte編碼基本一樣。

    * UCS-4: 4byte編碼, 目前是在UCS-2前加上2個全零的byte。 Unicode:

Unicode(統一碼、萬國碼、單一碼)是一種在計算機上使用的字元編碼。

它是 http://www.unicode.org制定的編碼機制, 要将全世界常用文字都函括進去。

它為每種語言中的每個字元設定了統一并且唯一的二進制編碼,以滿足跨語言、跨平台進行文本轉換、處理的要求。

1990年開始研發,1994年正式公布。随着計算機工作能力的增強,Unicode也在面世以來的十多年裡得到普及。

但自從unicode2.0開始,unicode采用了與ISO 10646-1相同的字庫和字碼,ISO也承諾ISO10646将不會給超出0x10FFFF的UCS-4編碼指派,使得兩者保持一緻。

Unicode的編碼方式與ISO 10646的通用字元集(Universal Character Set,UCS)概念相對應,目前的用于實用的Unicode版本對應于UCS-2,使用16位的編碼空間。

也就是每個字元占用2個位元組,基本滿足各種語言的使用。實際上目前版本的Unicode尚未填充滿這16位編碼,保留了大量空間作為特殊使用或将來擴充。 UTF:

Unicode 的實作方式不同于編碼方式。

一個字元的Unicode編碼是确定的,但是在實際傳輸過程中,由于不同系統平台的設計不一定一緻,以及出于節省空間的目的,對Unicode編碼的實作方式有所不同。

Unicode的實作方式稱為Unicode轉換格式(Unicode Translation Format,簡稱為 UTF)。

    * UTF-8: 8bit變長編碼,對于大多數常用字元集(ASCII中0~127字元)它隻使用單位元組,而對其它常用字元(特别是北韓和漢語會意文字),它使用3位元組。

    * UTF-16: 16bit編碼,是變長碼,大緻相當于20位編碼,值在0到0x10FFFF之間,基本上就是unicode編碼的實作,與CPU字序有關。

漢字編碼:

    * GB2312字集是簡體字集,全稱為GB2312(80)字集,共包括國标簡體漢字6763個。

    * BIG5字集是台灣繁體字集,共包括國标繁體漢字13053個。

    * GBK字集是簡繁字集,包括了GB字集、BIG5字集和一些符号,共包括21003個字元。

    * GB18030是國家制定的一個強制性大字集标準,全稱為GB18030-2000,它的推出使漢字集有了一個“大一統”的标準。 ANSI和Unicode big endia:

我們在Windows系統中儲存文本檔案時通常可以選擇編碼為ANSI、Unicode、Unicode big endian和UTF-8,這裡的ANSI和Unicode big endia是什麼編碼呢?

ANSI:

使用2個位元組來代表一個字元的各種漢字延伸編碼方式,稱為ANSI編碼。

在簡體中文系統下,ANSI編碼代表GB2312編碼,在日文作業系統下,ANSI編碼代表JIS編碼。

Unicode big endia:

UTF-8以位元組為編碼單元,沒有位元組序的問題。UTF-16以兩個位元組為編碼單元,在解釋一個UTF-16文本前,首先要弄清楚每個編碼單元的位元組序。

Unicode規範中推薦的标記位元組順序的方法是BOM(即Byte Order Mark)。

在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。

Windows就是使用BOM來标記文本檔案的編碼方式的。 三、程式設計語言與編碼 C、C++、Python2内部字元串都是使用目前系統預設編碼

Python3、Java内部字元串用Unicode儲存

Ruby有一個内部變量$KCODE用來表示可識别的多位元組字元串的編碼,變量值為"EUC" "SJIS" "UTF8" "NONE"之一。

$KCODE的值為"EUC"時,将假定字元串或正規表達式的編碼為EUC-JP。

同樣地,若為"SJIS"時則認定為Shift JIS。若為"UTF8"時則認定為UTF-8。

若為"NONE"時,将不會識别多位元組字元串。

在向該變量指派時,隻有第1個位元組起作用,且不區分大小寫字母。

"e" "E" 代表 "EUC","s" "S" 代表 "SJIS","u" "U" 代表 "UTF8",而"n" "N" 則代表 "NONE"。

預設值為"NONE"。

即預設情況下Ruby把字元串當成單位元組序列來處理。 四、為什麼會亂碼? 亂碼是個老問題,從上面我們知道,字元在儲存時的編碼格式如果和要顯示的編碼格式不一樣的話,就會出現亂碼問題。

我們的Web系統,從底層資料庫編碼、Web應用程式編碼到HTML頁面編碼,如果有一項不一緻的話,就會出現亂碼。

是以,解決亂碼問題說難也難說簡單也簡單,關鍵是讓互動系統之間編碼一緻。 五、有沒有萬金油? 在如此多種編碼和字元集弄的我們眼花缭亂的情況下,我們隻需選擇一種相容性最好的編碼方式和字元集,讓它成為我們程式子系統之間

互動的編碼契約,那麼從此惱人的亂碼問題即将遠離我們而去 -- 這種相容性最好的編碼就是UTF-8!

畢竟GBK/GB2312是國内的标準,當我們大量使用國外的開源軟體時,UTF-8才是編碼界最通用的語言。       Unicode: unicode.org制定的編碼機制, 要将全世界常用文字都函括進去.

在1.0中是16位編碼, 由U+0000到U+FFFF. 每個2byte碼對應一個字元; 在2.0開始抛棄了16位限制, 原來的16位作為基本位平面, 另外增加了16個位平面, 相當于20位編碼, 編碼範圍0到0x10FFFF. UCS: ISO制定的ISO10646标準所定義的 Universal Character Set, 采用4byte編碼. Unicode與UCS的關系: ISO與unicode.org是兩個不同的組織, 是以最初制定了不同的标準; 但自從unicode2.0開始, unicode采用了與ISO 10646-1相同的字庫和字碼, ISO也承諾ISO10646将不會給超出0x10FFFF的UCS-4編碼指派, 使得兩者保持一緻. UCS的編碼方式:   UCS-2, 與unicode的2byte編碼基本一樣. UCS-4, 4byte編碼, 目前是在UCS-2前加上2個全零的byte. UTF: Unicode/UCS Transformation Format UTF-8, 8bit編碼, ASCII不作變換, 其他字元做變長編碼, 每個字元1-3 byte. 通常作為外碼. 有以下優點:

* 與CPU位元組順序無關, 可以在不同平台之間交流

* 容錯能力高, 任何一個位元組損壞後, 最多隻會導緻一個編碼碼位損失, 不會鍊鎖錯誤(如GB碼錯一個位元組就會整行亂碼) UTF-16, 16bit編碼, 是變長碼, 大緻相當于20位編碼, 值在0到0x10FFFF之間, 基本上就是unicode編碼的實作. 它是變長碼, 與CPU字序有關, 但因為最省空間, 常作為網絡傳輸的外碼.

UTF-16是unicode的preferred encoding. UTF-32, 僅使用了unicode範圍(0到0x10FFFF)的32位編碼, 相當于UCS-4的子集. UTF與unicode的關系: Unicode是一個字元集, 可以看作為内碼.

而UTF是一種編碼方式, 它的出現是因為unicode不适宜在某些場合直接傳輸和處理. UTF-16直接就是unicode編碼, 沒有變換, 但它包含了0x00在編碼内, 頭256位元組碼的第一個byte都是0x00, 在作業系統(C語言)中有特殊意義, 會引起問題. 采用UTF-8編碼對unicode的直接編碼作些變換可以避免這問題, 并帶來一些優點. 中國國标編碼: GB 13000: 完全等同于ISO 10646-1/Unicode 2.1, 今後也将随ISO 10646/Unicode的标準更改而同步更改. GBK: 對GB2312的擴充, 以容納GB2312字元集範圍以外的Unicode 2.1的統一漢字部分, 并且增加了部分unicode中沒有的字元. GB 18030-2000: 基于GB 13000, 作為Unicode 3.0的GBK擴充版本, 覆寫了所有unicode編碼, 地位等同于UTF-8, UTF-16, 是一種unicode編碼形式. 變長編碼, 用單位元組/雙位元組/4位元組對字元編碼. GB18030向下相容GB2312/GBK.

GB 18030是中國所有非手持/嵌入式計算機系統的強制實施标準. -------------------------------     什麼是 UCS 和 ISO 10646?

國際标準 ISO 10646 定義了 通用字元集 (Universal Character Set, UCS). UCS 是所有其他字元集标準的一個超集. 它保證與其他字元集是雙向相容的. 就是說, 如果你将任何文本字元串翻譯到 UCS格式, 然後再翻譯回原編碼, 你不會丢失任何資訊. UCS 包含了用于表達所有已知語言的字元. 不僅包括拉丁語,希臘語, 斯拉夫語,希伯來語,阿拉伯語,亞美尼亞語和喬治亞語的描述, 還包括中文, 日文和韓文這樣的象形文字, 以及 平假名, 片假名, 孟加拉語, 旁遮普語果魯穆奇字元(Gurmukhi), 泰米爾語, 印.埃納德語(Kannada), Malayalam, 泰國語, 寮國語, 漢語拼音(Bopomofo), Hangul, Devangari, Gujarati, Oriya, Telugu 以及其他數也數不清的語. 對于還沒有加入的語言, 由于正在研究怎樣在計算機中最好地編碼它們, 因而最終它們都将被加入. 這些語言包括 Tibetian, 高棉語, Runic(古代北歐文字), 埃塞俄比亞語, 其他象形文字, 以及各種各樣的印-歐語系的語言, 還包括挑選出來的藝術語言比如 Tengwar, Cirth 和 克林貢語(Klingon). UCS 還包括大量的圖形的, 印刷用的, 數學用的和科學用的符号, 包括所有由 TeX, Postscript, MS-DOS,MS-Windows, Macintosh, OCR 字型, 以及許多其他字處理和出版系統提供的字元. ISO 10646 定義了一個 31 位的字元集. 然而, 在這巨大的編碼空間中, 迄今為止隻配置設定了前 65534 個碼位 (0x0000 到 0xFFFD). 這個 UCS 的 16位子集稱為 基本多語言面 (Basic Multilingual Plane, BMP). 将被編碼在 16 位 BMP 以外的字元都屬于非常特殊的字元(比如象形文字), 且隻有專家在曆史和科學領域裡才會用到它們. 按目前的計劃, 将來也許再也不會有字元被配置設定到從 0x000000 到 0x10FFFF 這個覆寫了超過 100 萬個潛在的未來字元的 21 位的編碼空間以外去了. ISO 10646-1 标準第一次發表于 1993 年, 定義了字元集與 BMP 中内容的架構. 定義 BMP 以外的字元編碼的第二部分 ISO 10646-2 正在準備中, 但也許要過好幾年才能完成. 新的字元仍源源不斷地加入到 BMP 中, 但已經存在的字元是穩定的且不會再改變了. UCS 不僅給每個字元配置設定一個代碼, 而且賦予了一個正式的名字. 表示一個 UCS 或 Unicode 值的十六進制數, 通常在前面加上 "U+", 就象 U+0041 代表字元"拉丁大寫字母A". UCS 字元 U+0000 到 U+007F 與 US-ASCII(ISO 646) 是一緻的, U+0000 到 U+00FF 與 ISO 8859-1(Latin-1) 也是一緻的. 從 U+E000 到 U+F8FF, 已經 BMP 以外的大範圍的編碼是為私用保留的. 什麼是組合字元?

UCS裡有些編碼點配置設定給了 組合字元.它們類似于打字機上的無間隔重音鍵. 單個的組合字元不是一個完整的字元. 它是一個類似于重音符或其他訓示标記, 加在前一個字元後面. 因而, 重音符可以加在任何字元後面. 那些最重要的被加重的字元, 就象普通語言的正字法(orthographies of common languages)裡用到的那種, 在 UCS 裡都有自己的位置, 以確定同老的字元集的向後相容性. 既有自己的編碼位置, 又可以表示為一個普通字元跟随一個組合字元的被加重字元, 被稱為 預作字元(precomposed characters). UCS 裡的預作字元是為了同沒有預作字元的舊編碼, 比如 ISO 8859, 保持向後相容性而設的. 組合字元機制允許在任何字元後加上重音符或其他訓示标記, 這在科學符号中特别有用, 比如數學方程式和國際音标字母, 可能會需要在一個基本字元後組合上一個或多個訓示标記. 組合字元跟随着被修飾的字元. 比如, 德語中的元音變音字元 ("拉丁大寫字母A 加上分音符"), 既可以表示為 UCS 碼 U+00C4 的預作字元, 也可以表示成一個普通 "拉丁大寫字母A" 跟着一個"組合分音符":U+0041 U+0308 這樣的組合. 當需要堆疊多個重音符, 或在一個基本字元的上面和下面都要加上組合标記時, 可以使用多個組合字元. 比如在泰國文中, 一個基本字元最多可加上兩個組合字元. 什麼是 UCS 實作級别?

不是所有的系統都需要支援象組合字元這樣的 UCS 裡所有的先進機制. 是以 ISO 10646 指定了下列三種實作級别: 級别1

不支援組合字元和 Hangul Jamo 字元 (一種特别的, 更加複雜的南韓文的編碼, 使用兩個或三個子字元來編碼一個韓文音節)

級别2

類似于級别1, 但在某些文字中, 允許一列固定的組合字元 (例如, 希伯來文, 阿拉伯文, Devangari, 孟加拉語, 果魯穆奇語, Gujarati, Oriya, 泰米爾語, Telugo, 印.埃納德語, Malayalam, 泰國語和寮國語). 如果沒有這最起碼的幾個組合字元, UCS 就不能完整地表達這些語言.

級别3

支援所有的 UCS 字元, 例如數學家可以在任意一個字元上加上一個 tilde(颚化符号,西班牙語字母上面的~)或一個箭頭(或兩者都加).

什麼是 Unicode?

曆史上, 有兩個獨立的, 創立單一字元集的嘗試. 一個是國際标準化組織(ISO)的 ISO 10646 項目, 另一個是由(一開始大多是美國的)多語言軟體制造商組成的協會組織的 Unicode 項目. 幸運的是, 1991年前後, 兩個項目的參與者都認識到, 世界不需要兩個不同的單一字元集. 它們合并雙方的工作成果, 并為創立一個單一編碼表而協同工作. 兩個項目仍都存在并獨立地公布各自的标準, 但 Unicode 協會和 ISO/IEC JTC1/SC2 都同意保持 Unicode 和 ISO 10646 标準的碼表相容, 并緊密地共同調整任何未來的擴充. 那麼 Unicode 和 ISO 10646 不同在什麼地方?

Unicode 協會公布的 Unicode 标準 嚴密地包含了 ISO 10646-1 實作級别3的基本多語言面. 在兩個标準裡所有的字元都在相同的位置并且有相同的名字. Unicode 标準額外定義了許多與字元有關的語義符号學, 一般而言是對于實作高品質的印刷出版系統的更好的參考. Unicode 詳細說明了繪制某些語言(比如阿拉伯語)表達形式的算法, 處理雙向文字(比如拉丁與希伯來文混合文字)的算法和 排序與字元串比較 所需的算法, 以及其他許多東西. 另一方面, ISO 10646 标準, 就象廣為人知的 ISO 8859 标準一樣, 隻不過是一個簡單的字元集表. 它指定了一些與标準有關的術語, 定義了一些編碼的别名, 并包括了規範說明, 指定了怎樣使用 UCS 連接配接其他 ISO 标準的實作, 比如 ISO 6429 和 ISO 2022. 還有一些與 ISO 緊密相關的, 比如 ISO 14651 是關于 UCS 字元串排序的. 考慮到 Unicode 标準有一個易記的名字, 且在任何好的書店裡的 Addison-Wesley 裡有, 隻花費 ISO 版本的一小部分, 且包括更多的輔助資訊, 因而它成為使用廣泛得多的參考也就不足為奇了. 然而, 一般認為, 用于列印 ISO 10646-1 标準的字型在某些方面的品質要高于用于列印 Unicode 2.0的. 專業字型設計者總是被建議說要兩個标準都實作, 但一些提供的樣例字形有顯著的差別. ISO 10646-1 标準同樣使用四種不同的風格變體來顯示表意文字如中文, 日文和韓文 (CJK), 而 Unicode 2.0 的表裡隻有中文的變體. 這導緻了普遍的認為 Unicode 對日本使用者來說是不可接收的傳說, 盡管是錯誤的. 什麼是 UTF-8?

首先 UCS 和 Unicode 隻是配置設定整數給字元的編碼表. 現在存在好幾種将一串字元表示為一串位元組的方法. 最顯而易見的兩種方法是将 Unicode 文本存儲為 2 個 或 4 個位元組序列的串. 這兩種方法的正式名稱分别為 UCS-2 和 UCS-4. 除非另外指定, 否則大多數的位元組都是這樣的(Bigendian convention). 将一個 ASCII 或 Latin-1 的檔案轉換成 UCS-2 隻需簡單地在每個 ASCII 位元組前插入 0x00. 如果要轉換成 UCS-4, 則必須在每個 ASCII 位元組前插入三個 0x00. 在 Unix 下使用 UCS-2 (或 UCS-4) 會導緻非常嚴重的問題. 用這些編碼的字元串會包含一些特殊的字元, 比如 '/0' 或 '/', 它們在 檔案名和其他 C 庫函數參數裡都有特别的含義. 另外, 大多數使用 ASCII 檔案的 UNIX 下的工具, 如果不進行重大修改是無法讀取 16 位的字元的. 基于這些原因, 在檔案名, 文本檔案, 環境變量等地方, UCS-2 不适合作為 Unicode 的外部編碼. 在 ISO 10646-1 Annex R 和 RFC 2279 裡定義的 UTF-8 編碼沒有這些問題. 它是在 Unix 風格的作業系統下使用 Unicode 的明顯的方法. UTF-8 有一下特性: UCS 字元 U+0000 到 U+007F (ASCII) 被編碼為位元組 0x00 到 0x7F (ASCII 相容). 這意味着隻包含 7 位 ASCII 字元的檔案在 ASCII 和 UTF-8 兩種編碼方式下是一樣的.

所有 >U+007F 的 UCS 字元被編碼為一個多個位元組的串, 每個位元組都有标記位集. 是以, ASCII 位元組 (0x00-0x7F) 不可能作為任何其他字元的一部分.

表示非 ASCII 字元的多位元組串的第一個位元組總是在 0xC0 到 0xFD 的範圍裡, 并指出這個字元包含多少個位元組. 多位元組串的其餘位元組都在 0x80 到 0xBF 範圍裡. 這使得重新同步非常容易, 并使編碼無國界, 且很少受丢失位元組的影響.

可以編入所有可能的 231個 UCS 代碼

UTF-8 編碼字元理論上可以最多到 6 個位元組長, 然而 16 位 BMP 字元最多隻用到 3 位元組長.

Bigendian UCS-4 位元組串的排列順序是預定的.

位元組 0xFE 和 0xFF 在 UTF-8 編碼中從未用到.

下列位元組串用來表示一個字元. 用到哪個串取決于該字元在 Unicode 中的序号. U-00000000 - U-0000007F:  0xxxxxxx 

U-00000080 - U-000007FF:  110xxxxx 10xxxxxx 

U-00000800 - U-0000FFFF:  1110xxxx 10xxxxxx 10xxxxxx 

U-00010000 - U-001FFFFF:  11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 

U-00200000 - U-03FFFFFF:  111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 

U-04000000 - U-7FFFFFFF:  1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx  xxx 的位置由字元編碼數的二進制表示的位填入. 越靠右的 x 具有越少的特殊意義. 隻用最短的那個足夠表達一個字元編碼數的多位元組串. 注意在多位元組串中, 第一個位元組的開頭"1"的數目就是整個串中位元組的數目. 例如: Unicode 字元 U+00A9 = 1010 1001 (版權符号) 在 UTF-8 裡的編碼為: 11000010 10101001 = 0xC2 0xA9 而字元 U+2260 = 0010 0010 0110 0000 (不等于) 編碼為: 11100010 10001001 10100000 = 0xE2 0x89 0xA0 這種編碼的官方名字拼寫為 UTF-8, 其中 UTF 代表 UCS Transformation Format. 請勿在任何文檔中用其他名字 (比如 utf8 或 UTF_8) 來表示 UTF-8, 當然除非你指的是一個變量名而不是這種編碼本身. 什麼程式設計語言支援 Unicode?

在大約 1993 年之後開發的大多數現代程式設計語言都有一個特别的資料類型, 叫做 Unicode/ISO 10646-1 字元. 在 Ada95 中叫 Wide_Character, 在 Java 中叫 char. ISO C 也詳細說明了處理多位元組編碼和寬字元 (wide characters) 的機制, 1994 年 9 月 Amendment 1 to ISO C 發表時又加入了更多. 這些機制主要是為各類東亞編碼而設計的, 它們比處理 UCS 所需的要健壯得多. UTF-8 是 ISO C 标準調用多位元組字元串的編碼的一個例子, wchar_t 類型可以用來存放 Unicode 字元.

繼續閱讀