字符编码那点事儿
那時(shí),天下人的口音、言語(yǔ),都是一樣。他們往東邊遷移的時(shí)候,在示拿地遇見一片平原,就住在那里。他們彼此商量說:“來(lái)吧!我們要作磚,把磚燒透了。”他們就拿磚當(dāng)石頭,又拿石漆當(dāng)灰泥。他們說:“來(lái)吧!我們要建造一座城和一座塔,塔頂通天,為要傳揚(yáng)我們的名,免得我們分散在全地上。”耶和華降臨,要看看世人所建造的城和塔。耶和華說:“看哪!他們成為一樣的人民,都是一樣的言語(yǔ),如今既作起這事來(lái),以后他們所要作的事,就沒有不成就的了。我們下去,在那里變亂他們的口音,使他們的言語(yǔ)彼此不通。”于是,耶和華使他們從那里分散在全地上;他們就停工不造那城了。因?yàn)橐腿A在那里變亂天下人的言語(yǔ),使眾人分散在全地上,所以那城名叫巴別。
——《創(chuàng)世記》?
字符、字符集、字符編碼
先說字符,字符大家都很清楚了,英文叫做character,通常的簡(jiǎn)寫叫做char,字符加上一種字體(Font),就可以得到字型(Glyph),字型就是我們眼前所見之物了。?
字符用來(lái)在計(jì)算機(jī)領(lǐng)域表示語(yǔ)言和文字,世間有無(wú)窮多字符,如果溝通的雙方要互相明白,就必須使用相同的字符集。字符集會(huì)規(guī)定一種或者幾種用計(jì)算機(jī)字節(jié)表示字符的方法,這個(gè)方法就叫做字符編碼。?ASCII?
ASCII恐怕是最最著名的字符集了,至今為止還有人將ASCII誤認(rèn)為是計(jì)算機(jī)中表示字符的方法的代稱,在任何編程系統(tǒng)中都會(huì)問"如何獲取某一字符的ASCII碼"。ASCII中共有127個(gè)字符,主要包含大小寫英文字母、標(biāo)點(diǎn)和一些控制符號(hào)。ASCII既是字符集,又是字符編碼,ASCII的每個(gè)字符對(duì)應(yīng)著0-127中的一個(gè)整數(shù),這個(gè)整數(shù)稱為字符的ASCII碼。例如,字符'a'的ASCII碼是97。
ASCII在計(jì)算機(jī)發(fā)展初期是非常NB的,這個(gè)時(shí)期主要是英語(yǔ)國(guó)家在使用計(jì)算機(jī),而對(duì)當(dāng)時(shí)的少數(shù)非英語(yǔ)國(guó)家用戶而言,英語(yǔ)根本不成為門檻,ASCII編碼可以放在一個(gè)Byte之中,這通常是計(jì)算機(jī)最小的空間單位。
哦對(duì)了,ASCII后來(lái)被國(guó)際標(biāo)準(zhǔn)化組織搞成了ISO/IEC 646,算是有了正式名分。
ASCII兼容編碼?
因?yàn)锳SCII對(duì)于英語(yǔ)之外的文字完全沒有考慮,?所以顯然沒法滿足全球人民日益增長(zhǎng)的字符使用需要,而由于ASCII編碼被廣泛使用,所以又沒法完完全全地重新發(fā)明一套新的字符集和編碼方式。
注意到ASCII只占用了0-127,但是一個(gè)字節(jié)其實(shí)可以表示256個(gè)數(shù)字,于是128到255或者說-128到-1這些值被一些人開始盯上了。于是一些ASCII兼容編碼開始出現(xiàn)了,其中我朝人民最為熟悉的就是GB2312了,unicode的UTF8編碼方式也是ASCII兼容的,這些后文再詳細(xì)分說。??
ASCII兼容是向下兼容,即某種編碼方式不需要經(jīng)過任何轉(zhuǎn)換接受任何以ASCII編碼的文本為合法的,并且字符與當(dāng)做ASCII編碼時(shí)是完全一致的。
幾乎所有的ASCII兼容編碼方式都是變長(zhǎng)編碼,因?yàn)槊總€(gè)ASCII字符只占一個(gè)字節(jié)。?
GB2312、GBK、GB18030
ASCII字符集里面不包括中文,那么顯然這對(duì)于我國(guó)人民的感情來(lái)說是難以接受的,于是黨和各級(jí)人民政府當(dāng)然不會(huì)允許這種事情發(fā)生。在倪光南院士等人的關(guān)懷下,1980年具有獨(dú)立自主知識(shí)產(chǎn)權(quán)的GB2312橫空出世了。
1995年,在社會(huì)主義偉大旗幟下,有關(guān)部門組織一些專家對(duì)GB2312做了一些擴(kuò)充,形成了GBK編碼,也就是GB13000標(biāo)準(zhǔn)。
2000年,為了滿足人民日益增長(zhǎng)的字符使用需要,我國(guó)又制定了GB18030標(biāo)準(zhǔn)。
GB系列的編碼還有一個(gè)稱呼叫做區(qū)位碼。
ANSI?
關(guān)于ANSI這種說不上是編碼方式還是字符集的充滿狗血故事的概念,還真是不太好講。好吧首先ANSI的意思是American National Standards Institute,美國(guó)國(guó)家標(biāo)準(zhǔn)學(xué)會(huì),嗯,但是很遺憾美國(guó)國(guó)家標(biāo)準(zhǔn)學(xué)會(huì)從來(lái)沒有制定過這么一個(gè)標(biāo)準(zhǔn),也不可能制定出來(lái)(好吧很快你就可以知道為什么了)。
最初這個(gè)東西如何出現(xiàn),現(xiàn)在已經(jīng)不可考證,但是毫無(wú)疑問至今windows的記事本保存選項(xiàng)里面仍然有這么一個(gè)叫做ANSI的選項(xiàng)。為什么說ANSI其實(shí)并不是一種字符集,也不是一個(gè)編碼呢?因?yàn)閷?shí)際上ANSI會(huì)隨著操作系統(tǒng)的區(qū)域和語(yǔ)言設(shè)置而變化!當(dāng)你將非unicode默認(rèn)語(yǔ)言選成中文時(shí),這個(gè)選項(xiàng)保存出來(lái)的文件赫然就是GB2312!對(duì)的!我認(rèn)為ANSI這個(gè)詞乃是米帝國(guó)主義亡我之心不死,妄圖將偉大社會(huì)主義字符編碼標(biāo)準(zhǔn)GB2312劃入米國(guó)之手啊!
好吧,認(rèn)真地說, ANSI這個(gè)概念頗為腦殘,它的實(shí)際意思是遵循本地化設(shè)置的編碼方式,但是卻不倫不類地扯上了米國(guó)國(guó)家標(biāo)準(zhǔn)學(xué)會(huì)。?
Unicode
講字符編碼一定不能漏了Unicode了,現(xiàn)在Unicode確實(shí)不負(fù)uni之名,是最有機(jī)會(huì)達(dá)成大統(tǒng)一重造巴別塔的一個(gè)字符集。Unicode的最新版本是6.0。
Unicode是一個(gè)字符集而不是一個(gè)編碼方式,Unicode中每個(gè)字符對(duì)應(yīng)一個(gè)code point(中譯為碼點(diǎn),覺得不喜歡這個(gè)翻譯) 。code point是一個(gè)0x00000到0x10FFFF之間的正整數(shù)。因此Unicode的字符都被記為U+XXXX,XXXX就是code point的16進(jìn)制表示了。
Unicode還把code point分成17個(gè)code plane,其中主要使用的是0,1,2,3四個(gè)平面,也就是U+0000-U+FFFF,U+10000-U+1FFFF,U+20000-U+2FFFF,U+30000-U+3FFFF這四個(gè)code point的集合。Unicode本身是抽象的,它發(fā)布的時(shí)候會(huì)帶一個(gè)參考字型但是實(shí)際上它把字型的決定權(quán)交給了字體,所以code point就是字符的唯一標(biāo)識(shí)了。
UTF
unicode本身并非編碼方式,所以u(píng)nicode需要編碼方式配合,常見的unicode編碼方式就是UTF。UTF-X的數(shù)字X就表示最少用幾個(gè)bit來(lái)表示一個(gè)字符。
常見的表示方式有UTF-8、UTF-16、UTF-32、UTF-7、UTF-24......
Unicode的?code plane共只有17個(gè),所以UTF-32已經(jīng)是定長(zhǎng)編碼了,它能表示的范圍是0x00000000到0xFFFFFFFF,這顯然遠(yuǎn)遠(yuǎn)超過現(xiàn)在Unicode的code point范圍,所以短期內(nèi)可以認(rèn)為UTF-32是定長(zhǎng)編碼。定長(zhǎng)編碼的好處是,獲取一個(gè)字符串的長(zhǎng)度可以直接根據(jù)它占用的內(nèi)存計(jì)算出,所以UTF家族中只有UTF-32可以享受到了。
UTF-8是最常用的UTF編碼,特別地,它還是ASCII兼容的。
值得注意的是,這些編碼里面,UTF-16使用甚廣,因?yàn)閡nicode1.0發(fā)布的時(shí)候,?UTF-16還可以認(rèn)為是定長(zhǎng)編碼,于是一些倒霉孩子比如Java就把UTF-16當(dāng)成自己的字符串在內(nèi)存中存儲(chǔ)使用的編碼,于是搞出來(lái)Char類型其實(shí)并不是每個(gè)表示一個(gè)字符,而是表示一個(gè)UTF-16 code unit這樣的人間慘劇。
UTF-8對(duì)英文文本來(lái)說是非常合適的,但是中文每個(gè)文字要占三個(gè)字節(jié),相比之下,UTF-16中的中文則是只占2個(gè)字節(jié),所以當(dāng)你的系統(tǒng)對(duì)存儲(chǔ)容量或者網(wǎng)絡(luò)流量敏感的時(shí)候,應(yīng)該根據(jù)你的文本主要組成方式選擇UTF恰當(dāng)?shù)木幋a。
大端和小端
對(duì)于UTF-16、UTF-32這種東西而言,還有一個(gè)很現(xiàn)實(shí)的問題,它們的code unit都是一個(gè)正整數(shù),而計(jì)算機(jī)系統(tǒng)的最小單位是字節(jié),字節(jié)表示正整數(shù)是有高位低位順序之分的,于是我們就有了大端小端的事情,相信用過window記事本的同學(xué)都有印象,里面有兩個(gè)選項(xiàng)unicode big endian和unicode,實(shí)際上這里unicode指的就是UTF-16編碼。?
BOM
BOM又叫做Byte Order Mark,起因是我們的unicode里面規(guī)定了一個(gè)神奇的字符零寬空格U+FEFF,這個(gè)字符好啊,它明明是個(gè)字符,還顯示不出來(lái),于是一些程序員大爺想出了個(gè)nb的辦法,約定所有的UTF數(shù)據(jù)流,都先吐出一個(gè)U+FEFF來(lái),反正又不會(huì)顯示出來(lái),根據(jù)這個(gè)U+FEFF的表示方法,就可以判斷數(shù)據(jù)流所使用的UTF編碼了。比如說,收到三個(gè)字節(jié)EF BB BF的話,就可以斷定來(lái)的編碼是UTF-8了。
這個(gè)NB辦法后來(lái)也被推廣到其它編碼上(嗯,比如GB就不行,跟BOM沖突,打開記事本輸入"聯(lián)通",然后保存為ANSI,再打開看看),也漸漸有了稱呼叫做BOM。但是很遺憾,不少人不懂規(guī)矩,不會(huì)在數(shù)據(jù)源前面加BOM,于是天下間的文本,又被分為了有BOM和無(wú)BOM兩種......?
UCS
很多人說Unicode的標(biāo)準(zhǔn)是ISO16406,實(shí)際上這話不對(duì),UCS才是。這中間有一段非常蛋疼的歷史,unicode和ucs是分別由兩個(gè)不同組織編寫和發(fā)布的不同標(biāo)準(zhǔn),但是因?yàn)槎咴诤茉缧r(shí)候就達(dá)成共識(shí),一直緊密合作,始終默契地保持兩份標(biāo)準(zhǔn)的一致,所以其實(shí)可以認(rèn)為Unicode就是UCS了。
然而跟Unicode不同,UCS本身還規(guī)定了編碼方式,主要有兩種:UCS-2和UCS-4,這里的2和4表示最少用幾個(gè)byte來(lái)表示一個(gè)字符。UCS-4也是定長(zhǎng)編碼,它跟UTF-32完全一致,所以二者只是理論上是兩種編碼而已。
值得注意的是,UCS-2與UTF-16是不完全一致的,UCS-2也是一種定長(zhǎng)編碼,code point超出0xFFFF的字符怎么辦呢?UCS-2......它表示不了這些字符!
ISO-8859
實(shí)際上,制定了自己的編碼標(biāo)準(zhǔn)的不僅僅是我們偉大的天朝,歐州國(guó)家也制定了一些自己的編碼規(guī)范,它們都是針對(duì)特定地區(qū)的編碼,不同語(yǔ)言使用不同字符集,所以互相之間不能混排,簡(jiǎn)單地說,就是跟GB2312一路貨色,這些東西也就是前面提到過的ANSI編碼了。
ISO-8859是一組規(guī)范,而不是一個(gè)規(guī)范,ISO-8859-1大家一定經(jīng)常在各處見到,它表示西歐字符集。ISO-8859家族現(xiàn)在一共有15個(gè),序號(hào)是從1排到16,除了12之外,關(guān)于為啥沒有12有些不同說法,又說原本是要給加入塞爾特語(yǔ)族的Latin-7,也有說是留給印度天體梵文的,總之就是因?yàn)橐恍┢婀值脑蛱^去了。
很遺憾我朝大佬對(duì)于ISO毫無(wú)興趣(也許ISO9001是例外?),因此GB始終是GB,沒能加入ISO當(dāng)中,不過GB基本可以認(rèn)為是跟ISO-8859同一體系的一種編碼。
結(jié)語(yǔ)
對(duì)于字符和編碼的這點(diǎn)事,我自己蛋疼了很久,才漸漸理解了其中錯(cuò)綜復(fù)雜的關(guān)系,這篇文章信息量不大,不過是個(gè)感性理解,希望對(duì)一些人會(huì)有幫助吧。?
from: http://www.cnblogs.com/winter-cn/archive/2012/01/27/2328512.html
總結(jié)
- 上一篇: 答与微博前端教主在吃饭时讨论到的一道微软
- 下一篇: 面试时算法题的解答思路