一、什么是字符集?什么是編碼?

字符(Character)是文字與符號的總稱,包括文字、圖形符號、數(shù)學(xué)符號等。
一組抽象字符的集合就是字符集(Charset)。
字符集常常和一種具體的語言文字對應(yīng)起來,該文字中的所有字符或者大部分常用字符就構(gòu)成了該文字的字符集,比如英文字符集。
一組有共同特征的字符也可以組成字符集,比如繁體漢字字符集、日文漢字字符集。
字符集的子集也是字符集。

計算機要處理各種字符,就需要將字符和二進制內(nèi)碼對應(yīng)起來,這種對應(yīng)關(guān)系就是字符編碼(Encoding)。
制定編碼首先要確定字符集,并將字符集內(nèi)的字符排序,然后和二進制數(shù)字對應(yīng)起來。根據(jù)字符集內(nèi)字符的多少,會確定用幾個字節(jié)來編碼。
每種編碼都限定了一個明確的字符集合,叫做被編碼過的字符集(Coded Character Set),這是字符集的另外一個含義。通常所說的字符集大多是這個含義。

二、有哪些字符集?

ASCII:
American Standard Code for Information Interchange,美國信息交換標準碼。
目前計算機中用得最廣泛的字符集及其編碼,由美國國家標準局(ANSI)制定。
它已被國際標準化組織(ISO)定為國際標準,稱為ISO 646標準。
ASCII字符集由控制字符和圖形字符組成。
在計算機的存儲單元中,一個ASCII碼值占一個字節(jié)(8個二進制位),其最高位(b7)用作奇偶校驗位。
所謂奇偶校驗,是指在代碼傳送過程中用來檢驗是否出現(xiàn)錯誤的一種方法,一般分奇校驗和偶校驗兩種。
奇校驗規(guī)定:正確的代碼一個字節(jié)中1的個數(shù)必須是奇數(shù),若非奇數(shù),則在最高位b7添1。
偶校驗規(guī)定:正確的代碼一個字節(jié)中1的個數(shù)必須是偶數(shù),若非偶數(shù),則在最高位b7添1。

ISO 8859-1:
ISO 8859,全稱ISO/IEC 8859,是國際標準化組織(ISO)及國際電工委員會(IEC)聯(lián)合制定的一系列8位字符集的標準,現(xiàn)時定義了15個字符集。
ASCII收錄了空格及94個“可印刷字符”,足以給英語使用。
但是,其他使用拉丁字母的語言(主要是歐洲國家的語言),都有一定數(shù)量的變音字母,故可以使用ASCII及控制字符以外的區(qū)域來儲存及表示。
除了使用拉丁字母的語言外,使用西里爾字母的東歐語言、希臘語、泰語、現(xiàn)代阿拉伯語、希伯來語等,都可以使用這個形式來儲存及表示。
    * 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編碼表示的字符范圍很窄,無法表示中文字符。
但是,由于是單字節(jié)編碼,和計算機最基礎(chǔ)的表示單位一致,所以很多時候,仍舊使用iso8859-1編碼來表示。
而且在很多協(xié)議上,默認使用該編碼。

UCS:
通用字符集(Universal Character Set,UCS)是由ISO制定的ISO 10646(或稱ISO/IEC 10646)標準所定義的字符編碼方式,采用4字節(jié)編碼。
UCS包含了已知語言的所有字符。
除了拉丁語、希臘語、斯拉夫語、希伯來語、阿拉伯語、亞美尼亞語、格魯吉亞語,還包括中文、日文、韓文這樣的象形文字,UCS還包括大量的圖形、印刷、數(shù)學(xué)、科學(xué)符號。
    * UCS-2: 與unicode的2byte編碼基本一樣。
    * UCS-4: 4byte編碼, 目前是在UCS-2前加上2個全零的byte。

Unicode:
Unicode(統(tǒng)一碼、萬國碼、單一碼)是一種在計算機上使用的字符編碼。
它是http://www.unicode.org制定的編碼機制, 要將全世界常用文字都函括進去。
它為每種語言中的每個字符設(shè)定了統(tǒng)一并且唯一的二進制編碼,以滿足跨語言、跨平臺進行文本轉(zhuǎn)換、處理的要求。
1990年開始研發(fā),1994年正式公布。隨著計算機工作能力的增強,Unicode也在面世以來的十多年里得到普及。
但自從unicode2.0開始,unicode采用了與ISO 10646-1相同的字庫和字碼,ISO也承諾ISO10646將不會給超出0x10FFFF的UCS-4編碼賦值,使得兩者保持一致。
Unicode的編碼方式與ISO 10646的通用字符集(Universal Character Set,UCS)概念相對應(yīng),目前的用于實用的Unicode版本對應(yīng)于UCS-2,使用16位的編碼空間。
也就是每個字符占用2個字節(jié),基本滿足各種語言的使用。實際上目前版本的Unicode尚未填充滿這16位編碼,保留了大量空間作為特殊使用或?qū)頂U展。

UTF:
Unicode 的實現(xiàn)方式不同于編碼方式。
一個字符的Unicode編碼是確定的,但是在實際傳輸過程中,由于不同系統(tǒng)平臺的設(shè)計不一定一致,以及出于節(jié)省空間的目的,對Unicode編碼的實現(xiàn)方式有所不同。
Unicode的實現(xiàn)方式稱為Unicode轉(zhuǎn)換格式(Unicode Translation Format,簡稱為 UTF)。
    * UTF-8: 8bit變長編碼,對于大多數(shù)常用字符集(ASCII中0~127字符)它只使用單字節(jié),而對其它常用字符(特別是朝鮮和漢語會意文字),它使用3字節(jié)。
    * UTF-16: 16bit編碼,是變長碼,大致相當(dāng)于20位編碼,值在0到0x10FFFF之間,基本上就是unicode編碼的實現(xiàn),與CPU字序有關(guān)。


漢字編碼:
    * GB2312字集是簡體字集,全稱為GB2312(80)字集,共包括國標簡體漢字6763個。
    * BIG5字集是臺灣繁體字集,共包括國標繁體漢字13053個。
    * GBK字集是簡繁字集,包括了GB字集、BIG5字集和一些符號,共包括21003個字符。
    * GB18030是國家制定的一個強制性大字集標準,全稱為GB18030-2000,它的推出使?jié)h字集有了一個“大一統(tǒng)”的標準。

ANSI和Unicode big endia:
我們在Windows系統(tǒng)中保存文本文件時通常可以選擇編碼為ANSI、Unicode、Unicode big endian和UTF-8,這里的ANSI和Unicode big endia是什么編碼呢?
ANSI:
使用2個字節(jié)來代表一個字符的各種漢字延伸編碼方式,稱為ANSI編碼。
在簡體中文系統(tǒng)下,ANSI編碼代表GB2312編碼,在日文操作系統(tǒng)下,ANSI編碼代表JIS編碼。
Unicode big endia:
UTF-8以字節(jié)為編碼單元,沒有字節(jié)序的問題。UTF-16以兩個字節(jié)為編碼單元,在解釋一個UTF-16文本前,首先要弄清楚每個編碼單元的字節(jié)序。
Unicode規(guī)范中推薦的標記字節(jié)順序的方法是BOM(即Byte Order Mark)。
在UCS編碼中有一個叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的編碼是FEFF。而FFFE在UCS中是不存在的字符,所以不應(yīng)該出現(xiàn)在實際傳輸中。
UCS規(guī)范建議我們在傳輸字節(jié)流前,先傳輸字符"ZERO WIDTH NO-BREAK SPACE"。
這樣如果接收者收到FEFF,就表明這個字節(jié)流是Big-Endian的;如果收到FFFE,就表明這個字節(jié)流是Little-Endian的。
因此字符"ZERO WIDTH NO-BREAK SPACE"又被稱作BOM。
Windows就是使用BOM來標記文本文件的編碼方式的。

三、編程語言與編碼

C、C++、Python2內(nèi)部字符串都是使用當(dāng)前系統(tǒng)默認編碼
Python3、Java內(nèi)部字符串用Unicode保存
Ruby有一個內(nèi)部變量$KCODE用來表示可識別的多字節(jié)字符串的編碼,變量值為"EUC" "SJIS" "UTF8" "NONE"之一。
$KCODE的值為"EUC"時,將假定字符串或正則表達式的編碼為EUC-JP。
同樣地,若為"SJIS"時則認定為Shift JIS。若為"UTF8"時則認定為UTF-8。
若為"NONE"時,將不會識別多字節(jié)字符串。
在向該變量賦值時,只有第1個字節(jié)起作用,且不區(qū)分大小寫字母。
"e" "E" 代表 "EUC","s" "S" 代表 "SJIS","u" "U" 代表 "UTF8",而"n" "N" 則代表 "NONE"。
默認值為"NONE"。
即默認情況下Ruby把字符串當(dāng)成單字節(jié)序列來處理。

四、為什么會亂碼?

亂碼是個老問題,從上面我們知道,字符在保存時的編碼格式如果和要顯示的編碼格式不一樣的話,就會出現(xiàn)亂碼問題。
我們的Web系統(tǒng),從底層數(shù)據(jù)庫編碼、Web應(yīng)用程序編碼到HTML頁面編碼,如果有一項不一致的話,就會出現(xiàn)亂碼。
所以,解決亂碼問題說難也難說簡單也簡單,關(guān)鍵是讓交互系統(tǒng)之間編碼一致。

五、有沒有萬金油?

在如此多種編碼和字符集弄的我們眼花繚亂的情況下,我們只需選擇一種兼容性最好的編碼方式和字符集,讓它成為我們程序子系統(tǒng)之間
交互的編碼契約,那么從此惱人的亂碼問題即將遠離我們而去 -- 這種兼容性最好的編碼就是UTF-8!
畢竟GBK/GB2312是國內(nèi)的標準,當(dāng)我們大量使用國外的開源軟件時,UTF-8才是編碼界最通用的語言。

 

http://www.javaeye.com/topic/97803

發(fā)表于 @ 2008年11月12日 15:12:00