字符集與編碼

itbsl發表於2022-04-19

一個位元(bit)可以是0,或者是1,8個位元(bit),組成一個位元組(byte)。全為0時代表數字0,全為1時代表數字255。

一個位元組可以表示256個數字,兩個位元組可以表示65536個數字。

更多的位元組,可以有更多的組合,就可以表示更大的數值範圍。

整數可以這麼存,那字元呢?一堆二進位制的0和1,怎麼也算不出字母A吧。不能直接表示,那就通過數字中轉一下。只要給它指定一個數值編號,要儲存字元時,就儲存這個數值。要讀取時,按照對映關係找到這個字元。

像這樣收錄許多字元然後給它們一一編號,得到一個字元編號對照表,這就是“字符集”。

ASCII字符集只收錄了128個字元,其擴充套件字符集也只有256個。(ASCII最初被設計的目的也只是用來對映英文體系所需要的字元)

這在只使用英文的國家貌似沒什麼問題,但是隨著世界的互聯,其它非英語母語的國家該怎麼辦呢?比如漢字、日文等。

針對漢字,最先設計了GB2312字符集、但是GB2312不包含繁體字,所以又設計了BIG5字符集,但是依然有很多字元沒有被收錄,其它國家的字型也不在其中

與其不斷推出收錄更多字元的字符集,還不如本著全球化統一標準的目的,製作一個通用字符集,Unicode學術學會就是這樣做的,這個字符集就是Unicode,它於1990年開始研發並於1994年正式公佈,實現了跨語言跨平臺的文字轉換與處理,字符集促成了字元與二進位制的合作。但是有了字符集就萬事大吉了嗎?那怎麼儲存(eggo世界)這個內容呢?

直接的想法是,找到每個字元對應的編號,存成二進位制,如果使用unicode字符集,拿到他們的編號,直接組合會得到這樣一大串二進位制位

問題出現了,該怎麼知道這一長串內容是要按照下面的方式劃分的呢?

也可以按照下面的方式劃分呀

所以,照搬編號的方式,行不通!!!

那現在我們可以知道了,編碼完成之後還需要解決的一個問題是如何劃分字元邊界。

其中一個方法可以這樣,不管編號多大多小,統一按照最長的編碼的來,位數不夠的高位補0嘛

這就是定長編碼,這樣就可以解決字元邊界的問題,但是可以發現,這樣就太浪費記憶體了,而且字符集收錄的符號越多,編號跨度就越大,定長編碼造成的浪費就越顯著,還得再想辦法,定長編碼不行,那就“變長編碼”,小編號少佔位元組,大編號多佔位元組。

但是怎麼劃分字元邊界呢?來看一種解決方案,如果編號屬於[0,127],就佔用一個位元組,且最高位固定標識為0。如果屬於[128,2047],就佔用兩個位元組,且有固定標識位110和10,三個以及更多位元組的編碼也遵循這樣的規則

以二進位制數字01100101,這個位元組最高位是零,就表示這個字元只佔一個位元組,除去標識位,剩下的7位就是該字元的二進位制編號,轉換成十進位制就是101,對應字元e,“世”字同理。

這樣劃分字元就不成問題了。剛剛我們做的是解碼,現在來編碼試試,世界的“界”字在Unicode字符集中編號為30028,符合區間[2048,65535],所以要佔用三位元組,使用下面這個模板。

然後將編號30028轉換成二進位制01110101 01001100,再對應填到模板中

好的,這樣就編碼完成了, 我們剛剛用的其實就是UTF-8編碼,也就是Go語言預設的編碼方式。

相關文章