我對字符集和字符編碼的理解
先定義兩個概念。
字符集
字符集就是把字符和一串數字(碼點)一一對應起來。GB2312,GBK,UNICODE,這些都是字符集。
字符編碼
字符編碼就是取得字符集中和字符對應的那串數字(字符編碼)之後,基於取得的那串數字再生成另外一串數字。utf8,utf16,utf32這些都是字符編碼。
字符集和字符編碼的關系
我們可以把字符集看作一個函數,F(字符)=string1
我們也可以把字符編碼看作另外一個函數,G(F(字符))=string2
string1即可以等於string2,也可以不等。
當string1等於string2的時候,意味著字符編碼的碼點就是字符編碼。比如GBK,GB2312
當string2不等於string2的時候,意味著字符集和字符編碼是不相同的,比如一個漢字的unicode字符集的結果是和utf8編碼的結果是不一樣的。
舉個例子:
飛的unicode碼點是0x98DE,這個網站可以查詢:https://bianma.supfree.net/
下面是一張utf8編碼規則表:
0x98DE在0000 0800 -0000 FFFF這個區間內,所以應該用第三行編碼規則。
先把0x98DE轉化為二進制:1001 1000 1101 1110 共有16個二進制數字。
1110xxxx 10xxxxxx 10xxxxxx ,這裏面共有16個x,就是16個空,我們把上面那串數字按照順序填寫進來就可以了。
1110100110100011 10011110
再舉個例子
飛的GBK編碼,經過網站查詢飛在字符集中的碼點是0xB7C9,那飛的GBK編碼就是0xB7C9。
為什麽UNICODE字符集的碼點不能作為字符編碼?
直接把UNICODE字符集的碼點拿來當作字符編碼就可以了嗎?為啥非要再折騰一下呢?因為UNICODE是兼容ASCII碼的,ASCII碼是一個字節對應一個字符,而如果把UNICODE字符集碼點當作字符編碼,UNICODE要編碼那麽多的字符,漢字、日文,必然會存在多個字節對應一個字符的情況,因為一個字節只能表示256種情況。好,我現在給你三個連續的字節,你怎麽解碼呢?你是把這三個字節依次當作三個字符解碼呢?還是把第一個字節當作一個字符解碼後面兩個字節當作另外一個字符解碼,還是前兩個字節當作一個字符解碼最後一個字節當作一個字符解碼?這時候我們就遇到問題了,怎麽辦? 想一想這個問題的關鍵點是在哪裏? 沒有一種機制告訴我們一個字節是應該按照一個字符解碼還是連續的兩個字節按照一個字符解碼。utf8 utf16 utf32就是幹這件事情的,它是怎麽做的。
還是上面那個飛的例子,飛的字符編碼應該是1110xxxx 10xxxxxx 10xxxxxx,看它最左邊那個字節的有三個連續的1了嗎?那就是告訴解碼程序,我這個字的字符編碼共有三個字節,如果最左邊的字節有連續的兩個1就表示這個字符是用兩個字節來編碼的。就是這麽簡單。
為什麽GBK GB2312字符集的碼點就能直接作為字符編碼?
查詢GBK編碼表可以知道它的字符編碼是在0x8140~0xFEA0這個範圍之內,看最高位的8到F
8到F這個範圍中會遇到8 9 A B C D E F這幾個數,把這幾個數轉換位二進制發現它們最高位的二進制位都是1,GBK編碼是除了ASCII碼之外所有的字符都用兩個字節編碼,GBK編碼是兼容ASCII碼的,ASCII碼的最高位一定是0,所以我們只需要檢測字節的最高位,如果是1,那麽就意味著這個字符共占用兩個字節,如果是0,那麽這個字符就占用一個字節。根本不會出現不知道怎麽解碼的問題。因為GBK GB2312的字符集已經把這個怎麽解碼的問題解決了,就不需要再折騰字符編碼那個步驟了。
我對字符集和字符編碼的理解