——每個軟體開發人員應該無條件掌握的知識!
——unicode偉大的創想!
相信大家一定碰到過,打開某個網頁,卻顯示一堆像亂碼,如"бЇЯАзЪСЯ"、"�????????"?還記得http中的accept-charset、accept-encoding、accept-language、content-encoding、content-language等消息頭字段?這些就是接下來我們要探讨的。
目錄:
<a href="http://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html#_1.%e5%9f%ba%e7%a1%80%e7%9f%a5%e8%af%86">1.基礎知識</a>
<a href="http://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html#_2.%e5%b8%b8%e7%94%a8%e5%ad%97%e7%ac%a6%e9%9b%86%e5%92%8c%e5%ad%97%e7%ac%a6%e7%bc%96%e7%a0%81">2.常用字元集和字元編碼</a>
<a href="http://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html#_2.1._ascii%e5%ad%97%e7%ac%a6%e9%9b%86&ascii%e7%bc%96%e7%a0%81">2.1. ascii字元集&編碼</a>
<a href="http://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html#_2.2._gbxxxx%e5%ad%97%e7%ac%a6%e9%9b%86&%e7%bc%96%e7%a0%81">2.2. gbxxxx字元集&編碼</a>
<a href="http://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html#_2.3._big5%e5%ad%97%e7%ac%a6%e9%9b%86&%e7%bc%96%e7%a0%81">2.3. big5字元集&編碼</a>
<a href="http://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html#_3.%e4%bc%9f%e5%a4%a7%e7%9a%84%e5%88%9b%e6%83%b3unicode">3.偉大的創想unicode</a>
<a href="http://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html#_3.1.ucs_&_unicode">3.1.ucs & unicode</a>
<a href="http://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html#_3.2.utf-32">3.2.utf-32</a>
<a href="http://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html#_3.3.utf-16">3.3.utf-16</a>
<a href="http://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html#_3.4.utf-8">3.4.utf-8</a>
<a href="http://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html#_4.accept-charset/accept-encoding/ac">4.accept-charset/accept-encoding/accept-language/content-type/content-encoding/content-language</a>
<a href="http://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html#_%e5%8f%82%e8%80%83%e6%96%87%e7%8c%ae&%e8%bf%9b%e4%b8%80%e6%ad%a5%e9%98%85%e8%af%bb">參考文獻&進一步閱讀</a>
計算機中儲存的資訊都是用二進制數表示的;而我們在螢幕上看到的英文、漢字等字元是二進制數轉換之後的結果。通俗的說,按照何種規則将字元存儲在計
算機中,如'a'用什麼表示,稱為"編碼";反之,将存儲在計算機中的二進制數解析顯示出來,稱為"解碼",如同密碼學中的加密和解密。在解碼過程中,如
果使用了錯誤的解碼規則,則導緻'a'解析成'b'或者亂碼。
字元集(charset):是一個系統支援的所有抽象字元的集合。字元是各種文字和符号的總稱,包括各國家文字、标點符号、圖形符号、數字等。
字元編碼(character encoding):是一套法則,使用該法則能夠對自然語言的字元的一個集合
(如字母表或音節表),與其他東西的一個集合(如号碼或電脈沖)進行配對。即在符号集合與數字系統之間建立對應關系,它是資訊處理的一項基本技術。通常人
們用符号集合(一般情況下就是文字)來表達資訊。而以計算機為基礎的資訊處理系統則是利用元件(硬體)不同狀态的組合來存儲和處理資訊的。元件不同狀态的
組合能代表數字系統的數字,是以字元編碼就是将符号轉換為計算機可以接受的數字系統的數,稱為數字代碼。
常見字元集名稱:ascii字元集、gb2312字元集、big5字元集、gb18030字元集、unicode字元集等。計算機要準确的處理各種字元集文字,需要進行字元編碼,以便計算機能夠識别和存儲各種文字。
ascii字元集:主要包括控制字元(Enter鍵、倒退、換行鍵等);可顯示字元(英文大小寫字元、阿拉伯數字和西文符号)。

圖1 ascii編碼表
圖2 擴充ascii編碼表
計算機發明之處及後面很長一段時間,隻用應用于美國及西方一些發達國家,ascii能夠很好滿足使用者的需求。但是當天朝也有了計算機之後,為了顯示中文,必須設計一套編碼規則用于将漢字轉換為計算機可以接受的數字系統的數。
天朝專家把那些127号之後的奇異符号們(即eascii)取消掉,規定:一個小于127的字元的意義與原來相同,但兩個大于127的字元連在一起
時,就表示一個漢字,前面的一個位元組(他稱之為高位元組)從0xa1用到
0xf7,後面一個位元組(低位元組)從0xa1到0xfe,這樣我們就可以組合出大約7000多個簡體漢字了。在這些編碼裡,還把數學符号、羅馬希臘的
字母、日文的假名們都編進去了,連在ascii裡本來就有的數字、标點、字母都統統重新編了兩個位元組長的編碼,這就是常說的"全角"字元,而原來在127
号以下的那些就叫"半角"字元了。
圖3 gb2312編碼表的開始部分
編碼空間龐大,最多可定義161萬個字元。
漢字收錄範圍包含繁體漢字以及日韓漢字
圖4 gb18030編碼總體結構
0x8140-0xa0fe
0xa140-0xa3bf
0xa3c0-0xa3fe
保留。此區沒有開放作造字區用。
0xa440-0xc67e
0xc6a1-0xc8fe
保留給使用者自定義字元(造字區)
0xc940-0xf9d5
0xf9d6-0xfefe
unicode字元集&utf編碼
——不得不單獨說unicode
像天朝一樣,當計算機傳到世界各個國家時,為了适合當地語言和字元,設計和實作類似gb232/gbk/gb18030/big5的編碼方案。這樣各搞一套,在本地使用沒有問題,一旦出現在網絡中,由于不相容,互相通路就出現了亂碼現象。
位元組的數字來表達每個字母、符号,或者表意文字(ideograph)。每個數字代表唯一的至少在某種語言中使用的符号。(并不是所有的數字都用上了,但
是總數已經超過了65535,是以2個位元組的數字是不夠用的。)被幾種語言共用的字元通常使用相同的數字來編碼,除非存在一個在理的語源學
(etymological)理由使不這樣做。不考慮這種情況的話,每個字元對應一個數字,每個數字對應一個字元。即不存在二義性。不再需要記錄"模式"
了。u+0041總是代表'a',即使這種語言沒有'a'這個字元。
一套包含了上标字、下标字等字元特性的枚舉等。unicode 組織(the unicode
consortium)是由一個非營利性的機構所運作,并主導 unicode 的後續發展,其目标在于:将既有的字元編碼方案以unicode
編碼方案來加以取代,特别是既有的方案在多語環境下,皆僅有有限的空間以及不相容的問題。
(可以這樣了解:unicode是字元集,utf-32/ utf-16/ utf-8是三種字元編碼方案。)
的參與者都認識到,世界不需要兩個不相容的字元集。于是,它們開始合并雙方的工作成果,并為創立一個單一編碼表而協同工作。從unicode
2.0開始,unicode采用了與iso 10646-1相同的字庫和字碼;iso也承諾,iso
10646将不會替超出u+10ffff的ucs-4編碼指派,以使得兩者保持一緻。兩個項目仍都存在,并獨立地公布各自的标準。但統一碼聯盟和
iso/iec
jtc1/sc2都同意保持兩者标準的碼表相容,并緊密地共同調整任何未來的擴充。在釋出的時候,unicode一般都會采用有關字碼最常見的字型,但
這種方法有其優點,最重要的一點就是可以在常數時間内定位字元串裡的第n個字元,因為第n個字元從第4×nth個位元組開始。雖然每一個碼位使用固定長定的位元組看似友善,它并不如其它unicode編碼使用得廣泛。
盡管有unicode字元非常多,但是實際上大多數人不會用到超過前65535個以外的字元。是以,就有了另外一種unicode編碼方式,叫做
utf-16(因為16位 =
2位元組)。utf-16将0–65535範圍内的字元編碼成2個位元組,如果真的需要表達那些很少使用的"星芒層(astral
plane)"内超過這65535範圍的unicode字元,則需要使用一些詭異的技巧來實作。utf-16編碼最明顯的優點是它在空間效率上比utf-
32高兩倍,因為每個字元隻需要2個位元組來存儲(除去65535範圍以外的),而不是utf-32中的4個位元組。并且,如果我們假設某個字元串不包含任何
星芒層中的字元,那麼我們依然可以在常數時間内找到其中的第n個字元,直到它不成立為止這總是一個不錯的推斷。其編碼方法是:
如果字元編碼u小于0x10000,也就是十進制的0到65535之内,則直接使用兩位元組表示;
如果字元編碼u大于0x10000,由于unicode編碼範圍最大為0x10ffff,從0x10000到0x10ffff之間
共有0xfffff個編碼,也就是需要20個bit就可以标示這些編碼。用u'表示從0-0xfffff之間的值,将其前 10 bit作為高位和16
bit的數值0xd800進行 邏輯or 操作,将後10 bit作為低位和0xdc00做 邏輯or 操作,這樣組成的
4個byte就構成了u的編碼。
對于utf-32和utf-16編碼方式還有一些其他不明顯的缺點。不同的計算機系統會以不同的順序儲存位元組。這意味着字元u+4e2d在utf-
16編碼方式下可能被儲存為4e 2d或者2d
4e,這取決于該系統使用的是大尾端(big-endian)還是小尾端(little-endian)。(對于utf-32編碼方式,則有更多種可能的位元組排列。)隻
要文檔沒有離開你的計算機,它還是安全的——同一台電腦上的不同程式使用相同的位元組順序(byte
order)。但是當我們需要在系統之間傳輸這個文檔的時候,也許在網際網路中,我們就需要一種方法來訓示目前我們的位元組是怎樣存儲的。不然的話,接收文檔
的計算機就無法知道這兩個位元組4e 2d表達的到底是u+4e2d還是u+2d4e。
為了解決這個問題,多位元組的unicode編碼方式定義了一個"位元組順序标記(byte order
mark)",它是一個特殊的非列印字元,你可以把它包含在文檔的開頭來訓示你所使用的位元組順序。對于utf-16,位元組順序标記是u+feff。如果收
到一個以位元組ff fe開頭的utf-16編碼的文檔,你就能确定它的位元組順序是單向的(one way)的了;如果它以fe
ff開頭,則可以确定位元組順序反向了。
128個us-ascii字元隻需一個位元組編碼(unicode範圍由u+0000至u+007f)。
在處理經常會用到的ascii字元方面非常有效。在處理擴充的拉丁字元集方面也不比utf-16差。對于中文字元來說,比utf-32要好。同時,
(在這一條上你得相信我,因為我不打算給你展示它的數學原理。)由位操作的天性使然,使用utf-8不再存在位元組順序的問題了。一份以utf-8編碼的文
檔在不同的計算機之間是一樣的比特流。
總體來說,在unicode字元串中不可能由碼點數量決定顯示它所需要的長度,或者顯示字元串之後在文本緩沖區中光标應該放置的位置;組合字元、變
寬字型、不可列印字元和從右至左的文字都是其歸因。是以盡管在utf-8字元串中字元數量與碼點數量的關系比utf-32更為複雜,在實際中很少會遇到有
不同的情形。
優點
使用标準的面向位元組的排序例程對utf-8排序将産生與基于unicode代碼點排序相同的結果。(盡管這隻有有限的有用性,因為在任何特定語言或文化下都不太可能有仍可接受的文字排列順序。)
utf-8字元串可以由一個簡單的算法可靠地識别出來。就是,一個字元串在任何其它編碼中表現為合法的utf-8的可能性很低,并随字元串長度
缺點
因為每個字元使用不同數量的位元組編碼,是以尋找串中第n個字元是一個o(n)複雜度的操作 — 即,串越長,則需要更多的時間來定位特定的字元。同時,還需要位變換來把字元編碼成位元組,把位元組解碼成字元。
accept-charset:浏覽器申明自己接收的字元集,這就是本文前面介紹的各種字元集和字元編碼,如gb2312,utf-8(通常我們說charset包括了相應的字元編碼方案);
accept-language:浏覽器申明自己接收的語言。語言跟字元集的差別:中文是語言,中文有多種字元集,比如big5,gb2312,gbk等等;
content-encoding:web伺服器表明自己使用了什麼壓縮方法(gzip,deflate)壓縮響應中的對象。例如:content-encoding:gzip
content-language:web伺服器告訴浏覽器自己響應的對象的語言。