Unicode與bytes有何區別?


我來嘗試回答一下,其實要討論編碼的問題,得從歷史說起。

在很久很久以前(笑),也就是ASCII碼時代,一個字元被編碼為一個Byte,我們都知道一個Byte對應了8bit,所以可以表示2^8 = 256個不同的字元。而我們的ASCII碼則是只使用了低7位bit來表示,一共2^7 = 128個字元。而事實上,就想下面這張表所表示的,ASCII碼的0~31號也不表示任何可見字元,而是控制字元,比如/t, /a什麼的。所以ASCII碼一共就表示了128-32 = 96個字元,分別是數字,大小寫字母和一些常見英文符號。ASCII碼就是如此單純而可愛。

但是人類的語言博大精深,永無止境的,特別是歐洲的小國家比如法國,西伯利亞,還有一些亂七八糟的字母。所以,大家開始利用這個1byte裡面的128及以上的碼號來表示一些特定的字母,因為標準不同,所以大家都沒有規定128及以上的碼號到底表示什麼,IBM就搞了個OEM字符集:

你可以看到,IBM維持了ASCII碼標準,但是添加了很多奇怪的西文符號和畫圖用的表格線等等。

但是IBM並不是唯一一家,很多不同國家的人開始肆無忌憚的利用多出來的這一個bit來表示自己國家的特定文字,這些不同的系統我們稱之為不同的Code Page。其實如果只是在本地操作,都還好,但是互聯網出現了,導致你用的這個Code Page,我用的那個Code Page,我們沒有辦法協調統一。而且最可惡的是,他們竟然忽略了亞洲,忽略了我博大精深的上千中國文字,怎麼可以在短短一個Byte裡面表示呢。

所以,Unicode應運而生了,事實上,Unicode把世界上所有國家的所有文字進行了映射,映射成了一個個叫做Code Point的代碼點(大概有2^20多個)比如Hello,對應的就是U+0048 U+0065 U+006C U+006C U+006F。Unicode還把所有的文字分成了2^16次方一組,一共17組。而第一組0~2^16叫做Basic Multilingual Plane,BMP。根據2~8原理,大部分正常人會用到的字元都在這個區間裡面。

因為代碼點不是固定長度的,所以為了正確存儲和表示這些代碼點,我們想到了運用編碼來解決這個問題。所以也就出現了我們常常聽見的UTF-16,UTF-32,UTF-8。

首先介紹UCS-4,其實它就是用4byte來表示所有的Unicode,因為4byte其實就可以把所有的Plane給包含了。當然這個問題也很明顯,就是佔用了太多空間了。

然後介紹一下UCS-2,也就是用2byte來表示Unicode的BMP。大部分情況下夠用,然後後來人們又用UTF-16取代了它。嚴格意義上UTF-16是變長的編碼方式。只不過現在大家似乎都習慣的接受了UTF-16是用2byte來表示,和UCS-2混用了。

我們稱前兩種叫做WCS(Wide Character Set,寬字符集),但大部分情況下,提及WCS,我們指的是UTF-16。因為涉及到2個Bytes,所以,就要考慮在不同CPU上如何分辨Little Endian還是Big Endian,所以這兩種表示法都需要BOM(Bye Order Mark)標誌(也就是在文檔開頭存「FEFF」,這樣程序讀取的時候就可以知道是Little Endian或者Big Endian了)。

但是用WCS有一個問題,就是它存在內存空間的浪費,所以人們又發明了UTF-8這種編碼方式。UTF-8中,0~127號字元都和ASCII碼一樣,用一個Byte存儲,只有128號及以上,採用多個Byte存儲(最多到6個Byte)。UTF-8有一個很好的優點,就是它對於ASCII碼是向下兼容的,所以英美國家的人用的時候分不出什麼區別,也方便了這種編碼方式的推廣。

所以綜上所述,Unicode是一個字符集,UTF-8,UTF-16,UTF-32都是這個字符集上的編碼方式。而ASCII,GBK等都是其它字符集,他們由於沒有像Unicode這樣將編碼和抽象表示解耦,所以默認都只有一個對應的編碼方式。

在vs中,對應了兩個數據結構,一個是wchar_t一個是char。其中char採用的是mbcs,通常是ascii碼,utf-8或者gbk(純中文字符集)。而wchar_t則是用的wcs,通常就是utf-16了。在字元「」或者""前加L就代表寬字元,比如L「我」。

所以你現在應該了解了Unicode和bytes的區別了。(我好像跑題了....)

參考資料:

[1] Jason Gregory說的程序員必讀博文之一 The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)

[2] Plane (Unicode)


不知道這個是不是某種編程語言相關的問題

一般來說,Unicode 只是一個「字符集」,它給每一個處於此字符集中的字元給予了一個編號。比如「我」,是 U+6211。

然後 Unicode 本身並不指定這個 U+6211 應該是什麼編碼什麼位元組序存儲和傳輸,那麼就有了編碼的這一概念。常見的比如 UTF-8、UTF-16 (LE)、UTF-16 (BE) 編碼等。可能這裡還會涉及到使用 BOM 來指定位元組序的問題。

那麼當編碼一定,位元組序一定的時候,存儲結果是肯定要落實到位元組(Bytes)上來的。

比如「我」字,U+6211,以 UTF-8 編碼(過程略),結果就是 E6 88 91 這三個位元組。

存儲、讀取或者傳輸的時候,見到的就是 E6 88 91。

可能還會見到 BOM - EF BB BF 在最前面。


推薦閱讀:

程序如何區分該顯示中文字元或英語字元?
字元在內存中最終的表示形式是什麼?是某種字元編碼還是碼位(Code Point)?
要往 Unicode 里添加符號需要經過什麼樣的流程?
給在美國的外國人發郵件,郵件中出現的漢字能正常顯示嗎?

TAG:Unicode統一碼 | 字元編碼 |