個人上篇文章,有朋友提出字符集和編碼的區別,我在此立文和你們討論下html
常說的字符集和編碼區別,其實就是編碼字符集和字符集編碼的區別,其實,單單若是隻是說字符集,沒有任何編碼的概念的話,那麼字符集其實僅僅是一個簡單的字符的集合,或者說是一個抽象的字符的集合,包括文字,符號等等,不參與任何存儲形式,只是存在這麼各類各樣標準的字符的集合node
若是僅僅是抽象的字符集,咱們是無需拿出討論的,由於沒有任何異議,通俗易懂,而常說的字符集指的編碼字符集,好比常見的 unicode、ascii、gb23十二、gbk等,這些咱們常稱作爲字符集(實際上是編碼字符集),這些字符集,好比unicode其實本質上是已經「編碼」過的字符集,即每一個字符都有惟一的整數編號,每一個字符都有本身特有的編號,同一個字符在不一樣編碼字符集中編號也會不一樣,固然不少編碼字符集都是ascll的超集,因此ascll字符集的編號與不少編碼字符集中編號都同樣,好比英文字母「A」,在ASCII及Unicode及GB2312中,均是第0x41個字符,說到這裏朋友必定注意到了我上面再描述「 unicode其實本質上是已經「編碼」過的字符集」中的「編碼」二字加了雙引號,我要強調的是這裏的「編碼」並非真的我下面要說的編碼,這裏只是爲每一個字符編了一個對應的編號,可是咱們仍是習慣專業的稱呼爲「編碼字符集」面試
咱們常常說「文章採用的是utf-8編碼方式」瀏覽器
我對於這個編碼方式的意義,我的理解是 將一個字符的整數編號用一個什麼二進制的整數值來對應並在計算機存儲。這和上面說的編碼字符集中的「編碼」千差萬別,這裏咱們稱之爲「字符集編碼」,即咱們常說的編碼post
說到這裏,不少人會以爲那麼unicode和utf-8的區別在哪裏?既然上文說到unicode是編碼字符集,那麼utf-8又是什麼?就是常說的編碼?編碼
「文章採用的是utf-8編碼方式」,我的以爲準確的說法是「文章採用的是基於unicode編碼字符集的utf-8的編碼方案」,即url
即unicode自己做爲編碼字符集沒有任何存儲形式,只是一個編號和字符對應的表而已,如何在計算機存儲?你可能想到了乾脆直接把編號看成二進制數值來直接存儲,那麼爲何不這麼作呢?這也算是一種字符集編碼方案,就是基於unicode編碼字符集的utf-32編碼方案,那麼有沒有更加智能一點的編碼方案呢?爲何會沒有呢?那就是utf-八、utf-16等等, 等等,在我解釋爲什麼要用utf-8編碼方案的時候,我必須說明一件事情:以下spa
我在上一篇文章《你不知道的 頁面編碼,瀏覽器選擇編碼,get,post各類亂碼由來》中說過:「如何查看中文字符的十六進制字符串?方法:BitConverter.ToString(System.Text.Encoding.UTF8.GetBytes("阿道夫"));」 請注意我能夠改成「System.Text.Encoding.Unicode.GetBytes」 以下圖是vs2013 Encoding鍵入「.」後的智能提示操作系統
(列表過長,用兩幅圖分別截圖).net
上圖有兩個疑問:
一、若是說unicode是編碼字符集,爲什麼會出如今和utf-8這種編碼方案並列的列表中?
二、ASCII或者gb2312都是編碼字符集爲什麼也會出如今和utf-8這種編碼方案並列的列表中?
咱們假設有兩個猜想:
一、此處的unicode並非真正的unicode編碼字符集,可能只是一種和unicode編碼字符集關係很是緊密的一種編碼方案
二、ASCII或者gb2312(其實就是圖中的Default,即操做系統當前的編碼,國內通常爲gb2312)是編碼字符集沒有錯,可是對於ASCII或者gb2312都只有惟一一種編碼,那麼我稱呼它們爲ASCII編碼或者GB2312編碼也沒有問題,既然這樣,那我把ascii和gb2312加入和utf-8這種編碼方案並列的列表中也理所固然?
個人兩個假設,很快獲得論證
一、在Encoding 的元數據看到:
1 // 2 // 摘要: 3 // 獲取使用 Little-Endian 字節順序的 UTF-16 格式的編碼。 4 // 5 // 返回結果: 6 // 使用 Little-Endian 字節順序的 UTF-16 格式的編碼。 7 public static Encoding Unicode { get; }
這裏解釋在這裏的unicode其實本質上「獲取使用 Little-Endian 字節順序的 UTF-16 格式的編碼」,即便基於unicode編碼字符集的utf-16編碼方案,相似的有BigEndianUnicode(獲取使用 Big Endian 字節順序的 UTF-16 格式的編碼)
二、通常的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 string param = "abc阿道夫"; 2 int length1 = System.Text.Encoding.Unicode.GetBytes(param).Length;//別忘了這裏的unicode本質是utf-16編碼方案 3 int length2 = param.Length;
那麼答案就是12和6了
最後,對於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