開始介紹 Unicode 之前,我們先來做一道不定項選擇題。
問題1:請問以下說法正確的是() |
答案文章末尾揭曉,如果著急想對答案可以先翻到末尾核對;如果想知道為什麼,那就帶著問題繼續往下看吧。
字符集
Unicode 是一種國際通用的字符集。
什麼是字符?計算機中的字符分為兩種:打印字符和非打印字符。打印字符包括數字、字母、漢字、假名、標點符號等等,非打印字符又稱之為控制字符,常見的有:回車(’\r’,U+000D)、換行(’\n’,U+000A)等等。
問題2:數字 123 由()個字符組成? |
什麼是字符集?字符集就是字符的集合,不同的字符集包含的字符類型和數量可能不一樣。Unicode 是字符集的一種。
字符之所以能被計算機處理,其中最為關鍵的是字符能夠被正確地編碼和解碼。字符的編碼是字符在對應字符集中的序號。此序號是一個整數,稱之為字符碼點 (code point)。不同的字符集可能會對同樣的字符有不同的碼點表示,甚至沒有表示(並不是所有字符在字符集中都有定義)。
問題3:有一種語言只有五種字符,暫記錄為「金木水火土」,請自定義碼表並說明需要多少個比特位進行編碼。 |
有人說:直接用一個整型來表示一個字符不就可以了嗎?可以是可以,不過整型大小固定 4 個字節,浪費空間。比如數字 123 使用 ASCII 字符集需要
常見的字符集有:
- US-ASCII(ISO646-US):美國信息交換標準代碼,1967年首次發表,1986年最後更新,7位,共 128 個字符。
- ISO-8859-1(ISO-LATIN-1):1980年發表,8位,共 256 個字符,兼容 US-ASCII。
- GB2312:國標2312,1980年發表,共 7,445 個字符,兼容 US-ASCII;
- GBK:國標擴展碼,1995年發表,共 21,886 個字符,兼容 GB2312。
- GB18030:國標18030,採用可變長編碼,每個字由 1、2 或 4 個字節組成,2000年發表,2005年更新,共 70,244 個字符,兼容 GBK,並實現了 Unicode 2.0 定義的碼位。
- Unicode:統一碼,1994年發表1.0,2021年發佈14.0版本。
Unicode
Unicode 碼點,取值範圍為 [U+0000, U+10FFFF]。
問題4:已知 Unicode碼點取值範圍為 [U+0000, U+10FFFF],請問最多可以表示()種字符? |
Unicode 碼點使用平面(Plane)進行歸類,有:
平面 | 始末字符值 | 用途 |
---|---|---|
0號平面(Plane 0) | U+0000 - U+FFFF |
基本多文種平面(Basic Multilingual Plane,簡稱 BMP),保留 U+D800 - U+DFFF 。 |
1號平面 | U+10000 - U+1FFFF |
多文種補充平面(Supplementary Multilingual Plane,簡稱 SMP) |
2號平面 | U+20000 - U+2FFFF |
表意文字補充平面(Supplementary Ideographic Plane,簡稱 SIP) |
3號平面 | U+30000 - U+3FFFF |
表意文字第三平面(Tertiary Ideographic Plane,簡稱 TIP) |
4號平面~13號平面 | U+40000 - U+DFFFF |
(尚未使用) |
14號平面 | U+E0000 - U+EFFFF |
特別用途補充平面(Supplementary Special-purpose Plane,簡稱 SSP) |
15號平面 | U+F0000 - U+FFFFF |
私人使用區(A區)(Private Use Area-A,簡稱 PUA-A) |
16號平面 | U+100000 - U+10FFFF |
私人使用區(B區)(Private Use Area-B,簡稱 PUA-B) |
值得注意的是:Unicode 只定義了碼點,而字符到具體的字節序列的映射由 UTF(Unicode/UCS Transformation Format 統一碼轉化格式) 實現。
UTF 目前有UTF-8、UTF-16 和 UTF-32。
問題5:Unicode的每個平面最多可以表示()種字符?BMP除去保留的區域外,共可以表示()種字符? |
UTF-8
UTF-8 是面向字節(8位)的 Unicode 編碼形式,使用一個、兩個、三個字節表示BMP上的字符,使用四個字節表示 BMP 外的字符。兼容 US-ASCII 字符集。
碼點位數 | 範圍 | 字節序列 | Byte 1 | Byte 2 | Byte 3 | Byte 4 |
---|---|---|---|---|---|---|
7 | U+0000 - U+007F |
1 | 0xxxxxxx |
|||
11 | U+0080 - U+07FF |
2 | 110xxxxx |
10xxxxxx |
||
16 | U+0800 - U+FFFF |
3 | 1110xxxx |
10xxxxxx |
10xxxxxx |
|
21 | U+10000 - U+10FFFF |
4 | 11110xxx |
10xxxxxx |
10xxxxxx |
10xxxxxx |
UTF-16
UTF-16 使用兩個字節來表示基本多語言平面,四個字節來表示輔助平面。
對於英文來說使用 UTF-8 省空間,對於中文來說UTF-16省空間,因為英文用 UTF-8 佔用 1 個字節,用 UTF-16 佔用 2 個字節;中文用 UTF-8 佔用 3 個字節,用 UTF-16 佔用 2 個字節。
碼點位數 | 範圍 | UTF-16 編碼形式(二進制) |
---|---|---|
16 | U+000000 - U+00FFFF |
xxxx xxxx xxxx xxxx |
20 | U+010000 - U+10FFFF |
1101 10yy yyyy yyyy 1101 11xx xxxx xxxx |
對於基本多語言平面,其編碼等同於其碼位。
對於輔助平面上的碼,編碼方式為:
- 減去 0x10000,成二進制形式:yyyy yyyy yyxx xxxx xxxx,共 20 位。
- 前 10 位為高位,加上 0xD800 作為前導代理(lead surrogates),值範圍:[0xD800, 0xDBFF]
- 後 10 位為低位,加上 0xDC00 作為後尾代理(trail surrogates),值範圍:[0xDC00, 0xDFFF]
- 可見前導和後尾的值不在同一個區間,最終形成:110110yyyyyyyyyy 110111xxxxxxxxxx
問題6:已知字符A的Unicode碼點為 U+0041,其UTF-8編碼和UTF-16編碼分別是? |
UTFs
UTF-16 編碼包含 BE (big endian)和 LE(little endian)版本,大端者,高位字節(MSB,most significant byte)在低地址;小端者,低位字節在低地址。
Name | UTF-8 | UTF-16 | UTF-16BE | UTF-16LE | UTF-32 | UTF-32BE | UTF-32LE |
---|---|---|---|---|---|---|---|
Smallest code point | 0000 | 0000 | 0000 | 0000 | 0000 | 0000 | 0000 |
Largest code point | 10FFFF | 10FFFF | 10FFFF | 10FFFF | 10FFFF | 10FFFF | 10FFFF |
Code unit size | 8 bits | 16 bits | 16 bits | 16 bits | 32 bits | 32 bits | 32 bits |
Byte order | N/A | <BOM> | big-endian | little-endian | <BOM> | big-endian | little-endian |
Fewest bytes per character | 1 | 2 | 2 | 2 | 4 | 4 | 4 |
Most bytes per character | 4 | 4 | 4 | 4 | 4 | 4 | 4 |
BOM
BOM,即 Byte Order Mark,字節序標記,用在文本文件的開頭。該標記為字符 U+FEFF,又稱為 ZWNBSP(ZERO WIDTH NO-BREAK SPACE,零寬非換行空格),表示大端字節序;相反的,U+FFFE(Noncharacters,非字符)表示小端字節序。
BOM字符的 UTF-8 編碼為 EF BB BF。UTF-8有 BOM編碼的文件會以 BOM 字符開頭。
UTF-8 不需要 BOM 來指定是小端還是大端字節序,但是可以通過 BOM 來區分是 UTF-8 編碼還是其他編碼。
問題7:請完成下列實操,並說說你對UTF-8編碼、BOM和CRLF的理解 |
問題答案
(問題1)CF。Unicode 採用邏輯序(logical order)編碼文本,比如會對英文從左到右編碼,而對希伯來文從右到左編碼,見:http://www.unicode.org/versions/Unicode3.0.0/ch02.pdf。UTF-16 編碼至少需要 2 個字節,ASCII 碼只需要 1 個字節,不兼容。
(問題2)3。很明顯1、2、3分別是3個字符。
(問題3)3。計算過程:
(問題4)1,114,112。計算過程:
(問題5)65536,63488。計算過程:
(問題6)0x41,0x0041。UTF-8表示A佔用1個字節,UTF-16則是佔用2個字節。
(問題7)
(1)「好」
Windows記事本:efbb bfe5 a5bb 0a
Vim:e5a5 bb0a
- efbb bf 是 BOM
- e5 a5bb 是「好」的UTF-8 編碼,1110 0101 1010 0101 1011 1101
- 0a 是 LF ‘\n’,換行符
(2)「好」+換行
Windows記事本:efbb bfe5 a5bb 0d0a
Vim:e5a5 bb0a
- 0d 是 CR ‘\r’ ,回車
結論:
- Windows記事本中的UTF-8編碼默認是帶BOM的,而Notepad++或Vim編輯器中的UTF-8編碼是無BOM的;
- Windows記事本中的換行符默認是 CRLF,而Notepad++或Vim編輯器中是Unix風格的 LF。