http://blog.jobbole.com/79610/
你不知道的 字符集和編碼(編碼字符集與字符集編碼)
常說的字符集和編碼區別,其實就是編碼字符集和字符集編碼的區別,其實,單單如果只是說字符集,沒有任何編碼的概念的話,那麼字符集其實僅僅是一個 簡單的字符的集合,或者說是一個抽象的字符的集合,包括文字,符號等等,不參與任何存儲形式,只是存在這麼各種各樣標準的字符的集合
如果僅僅是抽象的字符集,我們是無需拿出討論的,因為沒有任何異議,通俗易懂,而常說的字符集指的編碼字符集,比如常見的 unicode、ascii、gb2312、gbk等,這些我們常稱做為字符集(其實是編碼字符集),這些字符集,比如unicode其實本質上是已經 「編碼」過的字符集,即每個字符都有唯一的整數編號,每個字符都有自己特有的編號,同一個字符在不同編碼字符集中編號也會不同,當然很多編碼字符集都是 ascll的超集,所以ascll字符集的編號與很多編碼字符集中編號都一樣,比如英文字母「A」,在ASCII及Unicode及GB2312中,均是 第0×41個字符,說到這裡朋友一定注意到了我上面再描述「 unicode其實本質上是已經「編碼」過的字符集」中的「編碼」二字加了雙引號,我要強調的是這裡的「編碼」並不是真的我下面要說的編碼,這裡只是為每 個字符編了一個對應的編號,但是我們還是習慣專業的稱呼為「編碼字符集」
我們經常說「文章採用的是utf-8編碼方式」
我對於這個編碼方式的意義,個人理解是 將一個字符的整數編號用一個什麼二進制的整數值來對應並在計算機存儲。這和上面說的編碼字符集中的「編碼」千差萬別,這裡我們稱之為「字符集編碼」,即我們常說的編碼
說到這裡,很多人會覺得那麼unicode和utf-8的區別在哪裡?既然上文說到unicode是編碼字符集,那麼utf-8又是什麼?就是常說的編碼?
「文章採用的是utf-8編碼方式」,個人覺得準確的說法是「文章採用的是基於unicode編碼字符集的utf-8的編碼方案」,即
即unicode本身作為編碼字符集沒有任何存儲形式,只是一個編號和字符對應的表而已,如何在計算機存儲?你可能想到了乾脆直接把編號當作二進制 數值來直接存儲,那麼為什麼不這麼做呢?這也算是一種字符集編碼方案,就是基於unicode編碼字符集的utf-32編碼方案,那麼有沒有更加智能一點 的編碼方案呢?為什麼會沒有呢?那就是utf-8、utf-16等等, 等等,在我解釋為何要用utf-8編碼方案的時候,我必須說明一件事情:如下
我在上一篇文章《你不知道的 頁面編碼,瀏覽器選擇編碼,get,post各種亂碼由來》 中說過:「如何查看中文字符的十六進制字符串?方 法:BitConverter.ToString(System.Text.Encoding.UTF8.GetBytes(「阿道夫」));」 請注意我可以改為「System.Text.Encoding.Unicode.GetBytes」 如下圖是vs2013 Encoding鍵入「.」後的智能提示
(列表過長,用兩幅圖分別截圖)
上圖有兩個疑問:
1、如果說unicode是編碼字符集,為何會出現在和utf-8這種編碼方案並列的列表中?
2、ASCII或者gb2312都是編碼字符集為何也會出現在和utf-8這種編碼方案並列的列表中?
我們假設有兩個猜測:
1、此處的unicode並不是真正的unicode編碼字符集,可能只是一種和unicode編碼字符集關係非常緊密的一種編碼方案
2、ASCII或者gb2312(其實就是圖中的Default,即操作系統當前的編碼,國內一般為gb2312)是編碼字符集沒有錯,但是對於 ASCII或者gb2312都只有唯一一種編碼,那麼我稱呼它們為ASCII編碼或者GB2312編碼也沒有問題,既然這樣,那我把ascii和 gb2312加入和utf-8這種編碼方案並列的列表中也理所當然?
我的兩個假設,很快得到論證
1、在Encoding 的元數據看到:
1
2
3
4
5
6
7
| // // 摘要: // 获取使用 Little-Endian 字节顺序的 UTF-16 格式的编码。 // // 返回结果: // 使用 Little-Endian 字节顺序的 UTF-16 格式的编码。 public static Encoding Unicode { get ; } |
2、一般的ASCII或者gb2312,我們可以稱呼為ASCII字符集也可以稱呼為ASCII編碼,只是意義不同而已,因為對於ASCII編碼字符集或 者gb2312編碼字符集都只有唯一一種編碼,就是ASCII編碼和GB2312編碼,那麼列表中顯示的ASCII和GB2312指的不是編碼字符集而是 ASCII和GB2312的編碼方案,我想正是這種原因,才在很多時候,不管是字符集賦值還是編碼方案賦值都可以直接用gb2312或者ascii,比 如:
Encoding gb2312 = Encoding.GetEncoding(「gb2312〞);
Response.ContentEncoding = gb2312;//編碼
Response.Charset=」gb2312〞;//字符集
總結下的說:
就是unicode是字符集,不是編碼!但是ascii(gb2312)是字符集,這個說法肯定正確,但是我表達為「ascii編碼」也不能說大錯特錯,但是這種說法讓人誤解,如果一定要說那麼就說「ascii編碼字符集的編碼」
如果理解上面兩個假設的論證道理,那麼我們繼續討論之前暫停的話題,即「解釋為何要用utf-8等編碼方案(其他utf編碼方案類似)」
utf-8將很大一部分基於unicode編碼字符集的字符的整數編號作了變換後存儲在計算機中。(引用)以「漢」字為例,「漢」的Unicode值為 0x6C49,但其編碼為UTF-8格式後的值為0xE6B189(注意到變成了三個字節)。對於UTF-16編碼方案,則是對unicode編碼字符集 中的前65536個字符編號都不做變換,直接作為計算機存儲時使用的值(對65536以後的字符,仍然要做變換),例如「漢」字的Unicode編號為 0x6C49,那麼經過UTF-16編碼後存儲在計算機上時,它的表示仍為0x6C49,對於UTF-32編碼方案,他對所有的Unicode字符均不做 變換,直接使用編號存儲,只是這種編碼方案太浪費存儲空間(就連1個字節就可以搞定的英文字符,它都必須使用4個字節)
既然unicode編碼字符集有如此多的編碼方案,那麼
utf-8,字母數字符號等佔1字節,漢字佔三字節
utf-16,對unicode編碼字符集中的前65536個字符都佔兩個字節
utf-32,全部佔四字節
如果還有人問:
「unicode編碼每個字符佔幾個字節」,我們可以理直氣壯的說,第一unicode不是編碼!第二每個字符具體佔多少字節是要看編碼方案!
很多面試題會問:
1
2
3
| string param = "abc阿道夫" ; int length1 = System.Text.Encoding.Unicode.GetBytes(param).Length; //别忘了这里的unicode本质是utf-16编码方案 int length2 = param.Length; |
最後,對於gb2312或者ascii編碼字符集的字符的編號就是直接存儲在計算機中的二進制數,也就是說gb2312和ascii編碼字符集都只 有一種編碼方案,因為在gb2312編碼字符集中的ascii字符集部分的編號並沒有變化(即和ascii編碼字符集中的編碼一致),所以gb2312的 ascii部分字符存入計算機的二進制數還是佔用1個字節,而中文字符存入計算機的二進制數也是該中文字符在gb2312編碼字符集中的編號,該編號一般 轉換成二進制數都佔兩個字節,這個過程也就變成了所謂的gb2312編碼
如果上面的改為System.Text.Encoding.Default.GetBytes(param).Length,則值就是9和6了
如果需要瞭解更加深入的編碼內部原理請參考:
http://blog.csdn.net/nodeathphoenix/article/details/7057760
沒有留言:
張貼留言