1、ASCII
ASCII全稱(American Standard Code for Information Interchange)美國信息交換標准代碼,在計算機內部中8位二進制位組成1個字節(8(比特)bit=1(字節)byte),而ASCII的編碼方式是把一個字節中的低7位用來編碼,
最高位也就是第8位留着不用(最高位一般為0,但有時也被用作一些通訊系統的奇偶校驗位),從0x00一直編碼到0x7f(0000 0000 到 0111 1111),一共128個字符
2、ANSI
ANSI全稱(American National Standard Institite)美國國家標准學會(美國的一個非營利組織),首先ANSI不是指的一種特定的編碼,而是不同地區擴展編碼方式的統稱,各個國家和地區所獨立制定的兼容ASCII
但互相不兼容的字符編碼,微軟統稱為ANSI編碼
(GBK是在國家標准GB2312基礎上進行了擴容,包含的字符更多)
補充:在windows下輸入命令行的黑框下,右鍵再點擊屬性可以看到當前的編碼方式和代碼頁
代碼頁也稱為“內碼表”,是與特定語言的字符集相對應的一張表。操作系統中不同的語言和區域設置可能使用不同的代碼頁(代碼頁一般與其所直接對應的字符集之間並非完全等同,往往因為種種原因
(比如標准跟不上現實實踐的需要)而會對字符集有所擴展)
3、Unicode
Unicode 是一套字符集,而不是一套字符編碼,嚴格來說,字符集和字符編碼不是一個概念:
1、字符集定義了字符和二進制的對應關系,為每個字符分配了唯一的編號。可以將字符集理解成一個很大的表格,它列出了所有字符和二進制的對應關系,計算機顯示文字或者存儲文字,就是一個查表的過程。
2、而字符編碼規定了如何將字符的編號存儲到計算機中,如果使用了類似 GB2312 和 GBK 的變長存儲方案(不同的字符占用的字節數不一樣),那么為了區分一個字符到底使用了幾個字節,就不能將字符的編號
直接存儲到計算機中,字符編號在存儲之前必須要經過轉換,在讀取時還要再逆向轉換一次,這套轉換方案就叫做字符編碼。
有的字符集在制定時就考慮到了編碼的問題,是和編碼結合在一起的,例如 ASCII、GB2312、GBK、BIG5 等,所以無論稱作字符集還是字符編碼都無所謂,也不好區分兩者的概念。而有的字符集只管制定字符的編號,
至於怎么存儲,那是字符編碼的事情,Unicode 就是一個典型的例子,它只是定義了全球文字的唯一編號,我們還需要 UTF-8、UTF-16、UTF-32 這幾種編碼方案將 Unicode 存儲到計算機中。
(有興趣的讀取可以轉到 https://unicode-table.com/cn/ 查看 Unicode 包含的所有字符,以及各個國家的字符是如何分布的)
1、UTF-8
編碼方式:
1、如果只有一個字節,那么最高的比特位為 0,這樣可以兼容 ASCII;
2、如果有多個字節,那么第一個字節從最高位開始,連續有幾個比特位的值為 1,就使用幾個字節編碼,剩下的字節均以 10 開頭。
(對於常用的字符,它的 Unicode 編號范圍是 0 ~ FFFF,用 1~3 個字節足以存儲,只有及其罕見,或者只有少數地區使用的字符才需要 4~6個字節存儲)
具體的表現形式為:
- 0xxxxxxx:單字節編碼形式,這和 ASCII 編碼完全一樣,因此 UTF-8 是兼容 ASCII 的;
- 110xxxxx 10xxxxxx:雙字節編碼形式(第一個字節有兩個連續的 1);
- 1110xxxx 10xxxxxx 10xxxxxx:三字節編碼形式(第一個字節有三個連續的 1);
- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx:四字節編碼形式(第一個字節有四個連續的 1)
下面是具體的 Unicode 編號范圍與對應的 UTF-8 二進制格式
單字節可編碼的Unicode碼點值范圍十六進制為0x0000 ~ 0x007F,十進制為0 ~ 127;
雙字節可編碼的Unicode碼點值范圍十六進制為0x0080 ~ 0x07FF,十進制為128 ~ 2047;
三字節可編碼的Unicode碼點值范圍十六進制為0x0800 ~ 0xFFFF,十進制為2048 ~ 65535;
四字節可編碼的Unicode碼點值范圍十六進制為0x10000 ~ 0x1FFFFF,十進制為65536 ~ 2097151
上述的編號范圍幾個臨界值(127、2047、65535、2097151)的計算方式:
對於單字節來說除了前綴碼0,有效位數為7位,(2^7-1=127)
對於雙字節來說除了前綴碼110和10,有效位數為16-5=11位(2^11-1=2047)
剩下的三字節和四字節就是24-8=16位(2^16-1=65535)、32-11=21位(2^21-1=2097151)
將一個字符的Unicode編號確定對應編碼方式並按該編碼方式存儲的步驟如下:
以字母N為例,字母N的 Unicode編號為78(十進制),16進制編號為4E,78屬於0~127這個范圍,用單字節編碼(相當於ASCII)
2、 UTF-16
編碼方式:
1、對於 Unicode 編號范圍在 0 ~ FFFF 之間的字符,UTF-16 使用兩個字節存儲,並且直接存儲 Unicode 編號,不用進行編碼轉換,這跟 UTF-32 非常類似。
2、對於 Unicode 編號范圍在 10000~10FFFF 之間的字符,UTF-16 使用四個字節存儲,具體來說就是:將字符編號的所有比特位分成兩部分,較高的一些比特位用一個值介於 D800~DBFF 之間的雙字節存儲,
較低的一些比特位(剩下的比特位)用一個值介於 DC00~DFFF 之間的雙字節存儲。
3、UTF-32
編碼方式:
始終占用 4 個字節,足以容納所有的 Unicode 字符,所以直接存儲 Unicode 編號即可,不需要任何編碼轉換。浪費了空間,提高了效率。
對於上面這個字符來說對應的二進制為:0000 0000 1110 0110,經過UTF-32編碼后仍然為0000 0000 1110 0110,只不過這里需要說明的是,轉換成二進制后計算機存儲的問題,計算機在存儲器中排列字節有兩種方式:
大端法和小端法,大端法就是將高位字節放到低地址處,比如 0x1234, 計算機用兩個字節存儲,一個是高位字節 0x12,一個是低位字節 0x34,它的存儲方式為下:
(圖片來源:https://blog.csdn.net/zhusongziye/article/details/84261211)
UTF-32 用四個字節表示,處理單元為四個字節(一次拿到四個字節進行處理),如果不分大小端的話,那么就會出現解讀錯誤,比如我們一次要處理四個字節 12 34 56 78,這四個字節是表示
0x12 34 56 78 還是表示 0x78 56 34 12?不同的解釋最終表示的值不一樣。我們可以根據他們高低字節的存儲位置來判斷他們所代表的含義,所以在編碼方式中有UTF-32BE(big endian) 和 UTF-32LE(littleendian),分別對應大端和小端,來正確地解釋多個字節(這里是四個字節)的含義。
(Unicode規范中定義,每一個文件的最前面分別加入一個表示編碼順序的字符,這個字符的名字叫做"零寬度非換行空格"(ZERO WIDTH NO-BREAK SPACE),用FEFF表示,這正好是兩個字節,而且FF比FE大1,
如果一個文本文件的頭兩個字節是FE FF,就表示該文件采用大端方式;如果頭兩個字節是FF FE,就表示該文件采用小端方式)
對字符編碼感興趣的讀者可以看下笨笨阿林寫的刨根究底字符編碼的系列文章:https://www.cnblogs.com/benbenalin/