UTF-16
UTF-16是Unicode的一種可變長度的字元編碼形式。
它原來是最早期Unicode 1.0所想像,能用16位元的固定長去處理全世界所有文字的UCS-2。但自從Unicode 2.0新增補充平面後,16位元已經不足以表示Unicode內所有文字。所以UTF-16又設計了「代理對」的機制,以兩個16位元的組合去表達補充平面的文字。這讓UTF-16實質上也是一種可變長度的編碼方式。
編碼方式
基本多語言平面內的文字,Unicode碼位本身的值就是正確的UTF-16。意即 U+8140腀 的 UTF-16 值就是 0x8140。
代理對(surrogate pairs)
Unicode 2.0決定擴充原來的基本多語言平面,新增補充平面後,同時決定將 U+D800 到 U+DFFF 的碼位空下來,專作為UTF-16的代理字元使用。
凡是補充平面(即,非基本多語言平面的其他所有平面)的文字,就必須進行轉換,改以兩個代理字元組成。
代理對計算方式
- 以 U+1F63C😼 為例:
- 0x1F63C 減去 0x10000,結果為 0x0F63C,二進位為 0000 1111 0110 0011 1100 共20位。
- 將他的二進位前方10位數 00 0011 1101 (0x03D) 加上 0xD800 形成高位 0xD83D。
- 將他的二進位後方10位數 10 0011 1100 (0x23C) 加上 0xDC00 形成低位 0xDE3C。
- 以 U+2C9B0𬦰 為例
- 0x2C9B0 減去 0x10000,結果為 0x1C9B0,二進位為 0001 1100 1001 1011 0000 共20位。
- 將他的二進位前方10位數 00 0111 0010 (0x072) 加上 0xD800 形成高位 0xD872。
- 將他的二進位後方10位數 01 1011 0000 (0x1B0) 加上 0xDC00 形成低位 0xDDB0。
編碼序列
因為遙遠的歷史因素,各機器、作業系統處理16位元序列的順序都不一致。例如Windows與Linux習慣使用 Little Endian(低位在前);而TCP/IP、Java虛擬機器等習慣使用 Big Endian(高位在前)。
由於UTF-16是16位元編碼方式,也受到位元序列的影響,有UTF-16BE、UTF-16LE兩種序列形式。
碼位 | UTF-16 | UTF-16BE | UTF-16LE |
---|---|---|---|
U+0041A | 0041 | 00 41 | 41 00 |
U+20AC€ | 20AC | 20 AC | AC 20 |
U+2C9B0𬦰 | D872 DDB0 | D8 72 DD B0 | 72 D8 B0 DD |
請注意UTF-16BE與UTF-16LE的差異與代理對無關,而是每一個16位元序列之內的順序問題。
BOM
因為處理UTF-16兩種編碼序列時如果搞錯,會得到完全不同的結果,所以UTF-16純文字文件習慣在前面加上 U+FEFF 字元作為 BOM(Byte Order Mark;位元組順序標註)。在UTF-16BE序列上會是 FE FF
的序列,UTF-16LE序列上則是 FF FE
的序列,以便檢查文件的序列方式。
U+FEFF 字元本身的定義是不占空間也不換行的空格,所以理論上忽略BOM的處理,仍然不會影響到文件內容的正常解讀與處理。另外,依照UTF-8的規格,UTF-8序列中不會出現 0xFF 與 0xFE 的位元組,所以正好用來標示這是UTF-16文件。
使用環境
相較於UTF-8,雖然UTF-16的漢字只佔2 bytes,但所有ASCII字元也都佔用2 bytes的關係,所以平均而言會更佔空間。但因為UTF-16原先是固定長度的,對程式處理而言,16位元固定長度雖然會浪費一些儲存空間,但能帶來計算快速之類的好處(例如字串的切割、尋找第N個字,可以直接存取到正確位置,不需要從序列前方尋找),但隨著補充平面與代理對的出現,此優點已經消失。
故UTF-16主要使用在1996年之前(Unicode 1.0時代還沒有補充平面的時代)第一批支援Unicode的環境,例如Windows系統API、Java虛擬機器、Python 2、JavaScript等。這些實作很多到現在仍然將代理對視為兩個字處理,造成程式處理Emoji、擴充漢字時的困擾。
參考
- 建立於 2022 年 3 月 15 日 21 時 44 分
- 本條目共被 1 位不同作者編輯過 2 次
- 最後一次修改於 2022 年 3 月 16 日 01 時 22 分