字符集:ASCII、GB2312、GBK、GB18030、Unicode
文章目錄
- 1 字符集、代碼點、編碼的概念
- 2 字符集發展的脈絡
- 2.1 最早是ASCII
- 2.2 各個國家后續推出的編碼表
- 2.3 ANSI到底是什么編碼
- 3 ASCII
- 3.1 ASCII字符集簡介及其編碼的字符
- 3.2 ASCII字符集的代碼點
- 3.3 ASCII字符集的編碼方式
- 3.4 擴充的ASCII編碼
- 4 GB2312
- 4.1 GB2312字符集簡介及其編碼的字符
- 4.2 GB2312字符集的代碼點
- 4.3 GB2312字符集的編碼方式
- 5 GBK
- 6 GB18030
- 7 Unicode
- 7.1 Unicode介紹
- 7.2 UTF-8:變長的編碼規則
- 7.3 UTF-16:變長的編碼規則
- 7.4 UTF-32:定長的編碼規則
- 7.5 Unicode字符存儲的字節序問題
- 7.6 UTF-16和UTF-32的三種子風格、BOM
- 7.7 UCS-2和UCS-4
1 字符集、代碼點、編碼的概念
任何信息存儲在計算機中,都將是無差別的0和1的序列。所以,我們要想在計算機中存儲字符,那么,我們就需要對字符進行編碼,將字符編碼為計算機可以識別的0和1的序列。編碼就是將信息從一種形式轉換為另一種形式。
字符集:
在編碼之前,我們首先要確定,我們要對哪些字符進行編碼。然后,將這些需要進行編碼的字符集合到一起,這樣就形成了我們所說的字符集。常見的字符集有:ASCII、GBK、GB2312、Unicode等等。
代碼點:
字符集中的每一個字符都會被分配一個編號,這個編號我們稱之為代碼點。
需要注意如下:在ASCII字符集中,代碼點是從0開始依次遞增的 。但是,并非所有的字符集,代碼點都是從0開始依次遞增的。
編碼:
為了在計算機中存儲字符,我們需要將字符的代碼點轉換為0和1的序列,而這個轉換的過程,我們稱之為字符編碼。
要想在計算機存儲字符,需要經過如下5個步驟:
字符 --> 代碼點 --> 編碼 --> 0和1的序列(字符的編碼) --> 存儲到計算機中。
2 字符集發展的脈絡
2.1 最早是ASCII
最早出現的字符集是ASCII。
2.2 各個國家后續推出的編碼表
歐洲:ISO-8859-1、在ASCII基礎上的擴充(擴展ASCII編碼表)。
中國: GB2312 -> GBK -> GB18030(新的兼容舊的)。
臺灣: BIG5。
日本: JIS。
2.3 ANSI到底是什么編碼
ANSI對于不同語言的操作系統對應的編碼是不同的,如下:
- 簡體中文操作系統:GB2312。
- 繁體中文操作系統:Big5。
- 日文操作系統:JIS。
- 英文操作系統:ASCII。
3 ASCII
3.1 ASCII字符集簡介及其編碼的字符
使用一個字節來映射,映射了128個字符。只占用了最高位為0的8位二進制數來進行映射。
3.2 ASCII字符集的代碼點
在ASCII字符集中,代碼點是從0開始依次遞增的。
3.3 ASCII字符集的編碼方式
直接將代碼點編碼為它所對應的8位二進制數即可。
注意: 一個字節并非一定是8位,所以,嚴格來說應該是:轉換為它所對應的1個字節長的二進制數。
3.4 擴充的ASCII編碼
歐洲:ISO-8859-1、在ASCII基礎上的擴充(擴展ASCII編碼表)。
4 GB2312
4.1 GB2312字符集簡介及其編碼的字符
包括了漢字信息交換用的基本圖形字符。GB2312兼容ASCII,由兩個大于127的字節來映射我們增加的字符。發現最高位是0,那么就可以確定這個字節映射的就是ASCII的字符,那么就只讀取一個字節,然后去查ASCII表,然后將其解析為對應的字符。發現最高位是1,那么就可以確定這個字節映射的就是GB2312的字符,那么就連續讀兩個字節,然后去查GB2312,然后將其解析為對應的字符。
4.2 GB2312字符集的代碼點
GB2312字符集中,代碼點是根據區號和位號來安排的。
GB2312將字符劃分為了94個區(區號從1-94),每個區94個字符。字符在區里面的位置叫做位號(位號從1-94)。
比如:字符 <健>,它屬于第29區中的第一個字符那么,字符 <健>的區號就是29,位號就是1。
GB2312的代碼點計算方式如下:區號+32,位號+32 --> 代碼點,那么健的代碼點就是61,33。
+32的原因:
GB2312字符集除了兼容ASCII以外,它還對原ASCII中打印字符進行了2字節的編碼,就是我們平時所說的全角字符(第3區)。
全角字符在顯示和打印的時候,字符的輪廓占一個漢字的位置:
- AAA --> 半角
- AAA --> 全角
為了使全角字符的位號和它所對應的半角字符在ASCII中的代碼點保持一致,以方便它們之間的互轉。所以,我們對位號+32得到最終的代碼點 。區號為什么+32?暫時不知道,哈哈哈哈。
4.3 GB2312字符集的編碼方式
由于GB2312字符集兼容ASCII,所以,原ASCII的字符仍舊按照它原來的方法進行編碼(1個字節)。GB2312采用2個字節對自身的字符進行編碼:區號轉換為二進制存入高字節中,位號轉換為二進制數存入低字節中,兩個字節的最高位固定為1。
最高位固定為1的原因:
如果一個字節,它的最高位為0,那么,我們就可以判定這個字節存儲的是ASCII字符的編碼,我們就應該按照ASCII的字符編碼方法對它進行解析,得到正確的結果。如果一個字節,它的最高位為1,我們就可以判定這個字節及其后面的一個字節,存儲的是GB2312字符的編碼,我們就應該將這個字節及其后面的一個字節,按照GB2312的字符編碼方法對它進行解析,得到正確的結果。
5 GBK
隨著計算機的發展,它的普及率越來越高,它的應用場合也越來越多,而GB2312字符集中只有6763個漢字,而我們常用的漢字就有幾千個。顯然,這6763個漢字已經滿足不了越來越多的使用場合了。
因此,我們在GB2312字符集的基礎上進行了擴充,建立了GBK字符集:
6 GB18030
隨著時間的推進,我們在GBK字符集的基礎上又創建了GB18030字符集。
兼容性: ASCII(128) --> GB2312(7445) --> GBK(21886) --> GB18030(漢字70,244)。
7 Unicode
Unicode標準有兩套,不過后期這兩套標準基本上是一致的。
UNICODE協會:
- 字符集全稱:Universal Character Encoding
- 縮寫:UNICODE
- 翻譯:通用字符集編碼
ISO 10646工作組:
- 字符集全稱:Universal Coded Character Set
- 縮寫:UCS
- 翻譯:通用編碼字符集
- 標準號:ISO 10646
7.1 Unicode介紹
UNICODE字符集分為 17個區(標準的稱呼應該是 17個平面):
- 區號為: 0-16(0x00 - 0x10),每個區65536個字符。
- 位號為: 0-65535(0x0000 - 0xFFFF)。
代碼點: 高兩位十六進制數對應的是區號、低四位十六進制數對應的是位號 。
- 平面0的代碼點:0x00 0000 - 0x00 FFFF
- 平面1的代碼點:0x01 0000 - 0x01 FFFF
- 平面2的代碼點:0x02 0000 - 0x02 FFFF
- …
- 平面17的代碼點:0x10 0000 - 0x10 FFFF
由此可以發現:
代碼點表示方法:
- U+十六進制數字 ,比如:U+00 00FF(所以,上面表示代碼點的方法是錯誤的)。
低0區的字符:
- 第0區的字符是每個國家和地區的常用字符。也就是說,第0區混雜了各個國家常用的字符。
- 第0區又叫做:基本多語種平面。
思考:為什么這么做?
第0區代碼點的數值較小,所對應的編碼值也較小,這就意味著第0區代碼點更節省空間(我們不一定非要采用3個字節來對Unicode進行編碼)。那么很顯然,將使用較為頻繁的常用字符分配到第0區,就意味著更加節省空間。
UNICODE字符集的標準編碼規則是UTF-8、UTF-16、UTF-32,下面分別介紹。
7.2 UTF-8:變長的編碼規則
UTF-8以1個字節為單位,分別使用1個字節、2個字節、3個字節、4個字節對字符進行編碼。
( x的序列 --> 代碼點所對應的二進制形式 )
- 1個字節:對于平面0中的原ASCII字符,使用1個字節進行編碼(兼容ASCII)
- 0xxxxxxx (填充7位–>128種組合–>128個字符)?
- 2個字節:對于平面0中的原ASCII字符后面的1920個字符,使用2個字節進行編碼
- 110xxxxx 10xxxxxx (填充11位–>2048種組合–>2048個字符–>1920 +128=2048)
- 3個字節:對于平面0剩余的字符,使用3個字節進行編碼
- 1110xxxx 10xxxxxx 10xxxxxx (填充16位–>65536種組合–>65536個字符–>平面0:65536個字符)
- 4個字節:對于其它平面(輔助平面)的字符,使用4個字節進行編碼
- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx(填充21位–>?2097151?種組合–>2097151個字符–>遠遠高于字符集實際代碼點最大值)
7.3 UTF-16:變長的編碼規則
UTF-16以2個字節為單位,分別使用2個字節、4個字節對字符進行編碼(不兼容ASCII)。
( x的序列 --> 代碼點所對應的二進制形式 )
- 2個字節:對平面0的字符,使用2個字節進行編碼
- xxxxxxxx xxxxxxxx (16位–>65536種組合–>65536個字符–>平面0:65536個字符)
( z的序列 --> 代碼點所對應的二進制數 減去 0x10000 )
- 4個字節:對其它平面的字符,使用4個字節進行編碼??
- 110110zz zzzzzzzz 110111zz zzzzzzzz (填充20位–>1048576?種組合–>1048576個字符–>低于字符集實際代碼點最大值–>這也是-0x10000的原因??)
對于4字節的編碼來說:
- 高2字節取值范圍:11011000 00000000 - 11011111 11111111 --> D800-DBFF
- 低2字節取值范圍:11011100 00000000 - 11011111 11111111 --> DC00-DFFF
現在的問題是:對于2字節的編碼來說,也可能出現110110xx xxxxxxxx 或者 110111xx xxxxxxxx 這樣的編碼。意思就是:2字節的編碼,也可能是以 110110 或者 110111 作為開頭的。這時,我們就無法區分2個字節的數據,它到底是2個字節的編碼還是4個字節編碼的一部分。因為,高位上的 110110 和 110111 是我們進行區分的標識,而2字節編碼的高位也可能是一樣的數值。為了解決這個問題:UNICODE協會禁止 D800 - DFFF 區間的代碼點對應任何字符。這樣的話,2字節的編碼就避免了以 110110 或者 110111 開頭,因為,在這個區間的代碼點沒有對應任何字符。
7.4 UTF-32:定長的編碼規則
對每個代碼點都使用固定的4個字節進行編碼(不兼容ASCII),直接將代碼點所對應的二進制擴充為32位(高位補0)即可。
7.5 Unicode字符存儲的字節序問題
我們可以常常看到如下形式編碼:UTF-16LE、UTF-16BE、UTF-32LE、UTF -32BE 。為什么UTF-16和UTF-32的后面會有LE、BE的標志呢?為什么UTF-8的后面沒有LE、BE的標志呢?
UTF-8的存儲過程如下:
- UNICODE字符集 --> 代碼點 --> UTF-8 --> 編碼值 --> 存儲。
UTF-16和UTF-32的存儲過程如下:
- UNICODE字符集 --> 代碼點 --> UTF-16或UTF-32 --> 編碼值 --> 確認排序 --> 存儲。
為什么需要確認排序?字節順序會影響對數據的解析結果。
排序是排的哪部分的序?編碼單位內部的字節順序。
UTF-8字符存儲的字節序問題:
UTF-8編碼規則,是以字節為單位的。怎么理解呢?字節的存儲順序不影響對數據的解析結果 。所以,它不可能存在亂序的問題。所以,不需要排序。
比如,對于”小馬奔騰“(下面的編碼都是假設值,并不是真正的值):
- 小 --> 1字節編碼 0xxxxxxx
- 馬 --> 2字節編碼 110xxxxx 10xxxxxx
- 奔 --> 3字節編碼 1110xxxx 10xxxxxx 10xxxxxx
- 騰 --> 4字節編碼 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
實際的存儲情況:從第一個字符開始,順序存儲,且每個字符都從高字節開始存儲。存儲內容如下:
0xxxxxxx 110xxxxx 10xxxxxx 1110xxxx 10xxxxxx 10xxxxxx 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
如果我們按照從第一個字符開始,順序存儲,每個字符從低字節開始存儲,仍然不影響解析結果,因為每一個字符的最高字節都有特定的標志。存儲內容如下:
0xxxxxxx 10xxxxxx 110xxxxx 10xxxxxx 10xxxxxx 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx 11110xxx
UTF-16字符存儲的字節序問題:
UTF-16編碼規則,是以2字節為單位的。我們需要知道,2字節的存儲順序不影響對數據的解析結果 ,但是2字節內部的存儲順序則會影響對數據的解析結果。
比如,對于馬來說:
- 馬 --> 4字節編碼 110110zz zzzzzzzz 110111zz zzzzzzzz
是按照110110zz zzzzzzzz 110111zz zzzzzzzz這種格式存儲,還是按照110111zz zzzzzzzz 110110zz zzzzzzzz這種格式存儲,都不影響解析結果,因為對于4字節編碼,每個2字節中的高字節都有特定的開始標志。
實際的存儲情況:從第一個字符開始,順序存儲,且每個字符都是按照從高2字節開始存儲。
我們上面也說了,2字節內部的順序可以影響對數據的解析結果。看如下例子:
假設有如下兩個字的編碼:
- 奔 --> 4字節編碼 11011010 11011011 11011100 11011101
- 騰 --> 4字節編碼 11011011 11011010 11011101 11011100
對于兩字節內部的順序我們可以按照大端的格式存儲,也可以按照小端的格式存儲:
- BE Big-Endian – 大端:11011010 11011011 11011100 11011101
- LE Little-Endian – 小端:11011011 11011010 11011101 11011100
如果解析端未能按照正確的格式解析,就會出現字符解析錯誤的情況。所以,為了避免由于2字節內部的字節順序而導致數據被錯誤的解析,所以,UNICODE給我們提供了LE、BE的選擇。
那么對于UTF-16兩字節編碼也是同樣的情況:
假設有如下兩個字符的編碼:
- 小 --> 2字節編碼 10000000 00000000
- 馬 --> 2字節編碼 00000000 10000000
BE:
- 10000000 00000000
LE:
- 00000000 10000000
UTF-32字符存儲的字節序問題:
UTF-32編碼規則,是以4字節為單位的,且所有的字符都是固定的4個字節。所以,4字節內部的順序會影響對數據的解析,且存儲只存在兩種情況。
假設有如下兩個字符的編碼:
- 小 --> AA AB AC AD
- 馬 --> BA BB BC BD
對于不同的字符來說,一定是從第一個字符開始,順序存儲。
我們有如下兩種情況進行存儲:
- BE:AA AB AC AD
- LE:AD AC AB AA
所以,為了避免由于4字節內部的字節順序而導致數據被錯誤的解析,所以,UNICODE給我們提供了LE、BE的選擇。
7.6 UTF-16和UTF-32的三種子風格、BOM
BOM:
BOM(byte order mark:字節順序標記),放在文本的開頭,用于標識字節序。UTF-16編碼值:U+FE FF 、UTF-32編碼值:U+00 00 FE FF。
對于不帶BOM的編碼格式,則對于解析端則必須知道編碼格式才能正確解析,否則就會解析錯誤。
UTF-8帶BOM:
UTF-8可以帶BOM,但是,這并不會影響字符的存儲的字節順序。它僅僅是用來提示當前文本是使用UTF-8存儲的,僅此而已。
比如:
- 我 --> 使用UTF-8不帶BOM的實際存儲效果 --> E6 88 91
- 我 --> 使用UTF-8帶BOM的實際存儲效果 --> EF BB BF E6 88 91
UTF-16的三種子風格:
有如下字符:
UNICODE字符集 --> --> UTF-16 --> 編碼值:D8 00 DC FF
實際存儲效果:
- UTF -16BE --> D8 00 DC FF (windows會存儲為帶BOM的形式,如果其他系統下不會存儲為帶BOM的形式,那么解析的時候必須知道存儲格式才能解析成功,否則解析失敗,將亂碼)
- UTF -16LE --> 00 D8 FF DC (windows會存儲為帶BOM的形式)
- UTF-16
- –> 默認:D8 00 DC FF(實際對應BE)
- –> 帶BOM:FE FF D8 00 DC FF(實際對應BE)
–> 帶BOM:FF FE 00 D8 FF DC(實際對應LE)
UTF-32的三種子風格:
有如下字符:
UNICODE字符集 --> --> UTF-32 --> 編碼值:00 01 00 FF
實際存儲效果:
- UTF -32BE --> 00 01 00 FF (windows會存儲為帶BOM的形式)
- UTF -32LE --> FF 00 01 00 (windows會存儲為帶BOM的形式)
- UTF-32
- –> 默認:00 01 00 FF(實際對應BE)
- –> 帶BOM:00 00 FE FF 00 01 00 FF(實際對應BE)
- –> 帶BOM:FF FE 00 00 FF 00 01 00(實際對應LE)
注意: 不帶BOM的前提一定是編碼端和解析端已經統一了編碼規則!
7.7 UCS-2和UCS-4
關于UCS-2和UCS-4的內容參見如下博客即可:
細說:Unicode, UTF-8, UTF-16, UTF-32, UCS-2, UCS-4
參考資料:
總結
以上是生活随笔為你收集整理的字符集:ASCII、GB2312、GBK、GB18030、Unicode的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: cin
- 下一篇: 开一家美容院的资金预算 创业得先搞清楚自