你不知道的 字符集和編碼(編碼字符集與字符集編碼)


我的上篇文章,有朋友提出字符集和編碼的區別,我在此立文和大家討論下

常說的字符集和編碼區別,其實就是編碼字符集和字符集編碼的區別,其實,單單如果只是說字符集,沒有任何編碼的概念的話,那么字符集其實僅僅是一個簡單的字符的集合,或者說是一個抽象的字符的集合,包括文字,符號等等,不參與任何存儲形式,只是存在這么各種各樣標准的字符的集合

如果僅僅是抽象的字符集,我們是無需拿出討論的,因為沒有任何異議,通俗易懂,而常說的字符集指的編碼字符集,比如常見的 unicode、ascii、gb2312、gbk等,這些我們常稱做為字符集(其實是編碼字符集),這些字符集,比如unicode其實本質上是已經“編碼”過的字符集,即每個字符都有唯一的整數編號,每個字符都有自己特有的編號,同一個字符在不同編碼字符集中編號也會不同,當然很多編碼字符集都是ascll的超集,所以ascll字符集的編號與很多編碼字符集中編號都一樣,比如英文字母“A”,在ASCII及Unicode及GB2312中,均是第0x41個字符,說到這里朋友一定注意到了我上面再描述“ 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         //     獲取使用 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 格式的編碼)
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 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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM