UTF-16

本页面有特殊字符操作系统浏览器須支持特殊字母与符号才能正確显示,否则可能變成乱码、问号、空格等其它符号。

UTF-16是Unicode字符编码五层次模型的第三层:字符编码表(Character Encoding Form,也称为"storage format")的一种实现方式。即把Unicode字符集的抽象码位映射为16位长的整数(即码元)的序列,用于数据存储或传递。Unicode字符的码位,需要1个或者2个16位长的码元来表示,因此这是一个变长表示。

UTF是"Unicode/UCS Transformation Format"的首字母缩写,即把Unicode字符转换为某種格式之意。UTF-16正式定義於ISO/IEC 10646-1的附錄C,而RFC2781也定義了相似的做法。

UTF-16描述

Unicode的编码空间从U+0000到U+10FFFF,共有1,112,064个码位(code point)可用来映射字符。Unicode的编码空间可以划分为17个平面(plane),每个平面包含216(65,536)个码位。17个平面的码位可表示为从U+xx0000到U+xxFFFF,其中xx表示十六进制值从0016到1016,共计17个平面。第一个平面称为基本多语言平面(Basic Multilingual Plane, BMP),或稱第零平面(Plane 0),其他平面称为辅助平面(Supplementary Planes)。基本多语言平面內,從U+D800到U+DFFF之間的码位區段是永久保留不映射到Unicode字符。UTF-16就利用保留下来的0xD800-0xDFFF区段的码位來對輔助平面的字符的码位進行編碼。

从U+0000至U+D7FF以及从U+E000至U+FFFF的码位

第一个Unicode平面(码位从U+0000至U+FFFF)包含了最常用的字符。该平面被称为基本多语言平面,缩写为BMP(Basic Multilingual Plane,BMP)。UTF-16与UCS-2编码这个范围内的码位为16比特长的单个码元,数值等价于对应的码位。BMP中的这些码位是仅有的可以在UCS-2中表示的码位。

从U+10000到U+10FFFF的码位

辅助平面(Supplementary Planes)中的码位,在UTF-16中被编码为一对16比特长的码元(即32位元,4字節),称作代理对(Surrogate Pair),具体方法是:

UTF-16解碼
lead \ trail DC00 DC01    …    DFFF
D800 10000 10001 103FF
D801 10400 10401 107FF
  ⋮
DBFF 10FC00 10FC01 10FFFF
  1. 码位减去 0x10000,得到的值的范围为20比特长的 0...0xFFFFF
  2. 高位的10比特的值(值的范围为 0...0x3FF)被加上 0xD800 得到第一个码元或称作高位代理(high surrogate),值的范围是 0xD800...0xDBFF。由于高位代理比低位代理的值要小,所以为了避免混淆使用,Unicode标准现在称高位代理为前导代理(lead surrogates)。
  3. 低位的10比特的值(值的范围也是 0...0x3FF)被加上 0xDC00 得到第二个码元或称作低位代理(low surrogate),现在值的范围是 0xDC00...0xDFFF。由于低位代理比高位代理的值要大,所以为了避免混淆使用,Unicode标准现在称低位代理为后尾代理(trail surrogates)。

上述算法可理解为:辅助平面中的码位从U+10000到U+10FFFF,共计FFFFF个,即220=1,048,576个,需要20位来表示。如果用两个16位长的整数组成的序列来表示,第一个整数(称为前导代理)要容纳上述20位的前10位,第二个整数(称为后尾代理)容纳上述20位的后10位。还要能根据16位整数的值直接判明属于前导整数代理的值的范围(210=1024),还是后尾整数代理的值的范围(也是210=1024)。因此,需要在基本多语言平面中保留不对应于Unicode字符的2048个码位,就足以容纳前导代理与后尾代理所需要的编码空间。这对于基本多语言平面总计65536个码位来说,仅占3.125%。

由于前导代理、后尾代理、BMP中的有效字符的码位,三者互不重叠,搜索是简单的:一个字符编码的一部分不可能与另一个字符编码的不同部分相重叠。这意味着UTF-16是自同步(self-synchronizing)的:可以通过仅检查一个码元来判定给定字符的下一个字符的起始码元。UTF-8也有类似优点,但许多早期的编码模式就不是这样,必须从头开始分析文本才能确定不同字符的码元的边界。

由于最常有的字符都在基本多文种平面中,许多软件处理代理对的部分往往得不到充分的测试。这导致了一些长期的bug与潜在安全漏洞,它们甚至存在于广为流行且评价颇高的应用软件中[1]

从U+D800到U+DFFF的码位

Unicode标准规定U+D800...U+DFFF的值不对应于任何字符。

但是在使用UCS-2的时代,U+D800...U+DFFF内的值被占用,用于某些字符的映射。但只要不构成代理对,许多UTF-16编码解码还是能把这些不符合Unicode标准的字符映射正确的辨识、转换成合规的码元[2]。按照Unicode标准,这种码元序列本来应算作编码错误。

範例:

以U+10437编码(𐐷)为例:

  1. 0x10437 减去 0x10000,结果为0x00437,二进制为 0000 0000 0100 0011 0111
  2. 分割它的上10位值和下10位值(使用二进制):0000 0000 0100 0011 0111
  3. 添加 0xD800 到上值,以形成高位0xD800 + 0x0001 = 0xD801
  4. 添加 0xDC00 到下值,以形成低位0xDC00 + 0x0037 = 0xDC37
  • 下表总结了一起示例的转换过程,颜色指示码点位如何分布在所述的UTF-16中。由UTF-16编码过程中加入附加位的以黑色显示。
字符 普通二进制 UTF-16二进制 UTF-16 十六进制
字符代码
UTF-16BE
十六进制字节
UTF-16LE
十六进制字节
$ U+0024 0000 0000 0010 0100 0000 0000 0010 0100 0024 00 24 24 00
U+20AC 0010 0000 1010 1100 0010 0000 1010 1100 20AC 20 AC AC 20
𐐷 U+10437 0001 0000 0100 0011 0111 1101 1000 0000 0001 1101 1100 0011 0111 D801 DC37 D8 01 DC 37 01 D8 37 DC
𤭢 U+24B62 0010 0100 1011 0110 0010 1101 1000 0101 0010 1101 1111 0110 0010 D852 DF62 D8 52 DF 62 52 D8 62 DF

範例:UTF-16編碼程序

假設要將U+64321(16進位)轉成UTF-16編碼。因為它超過U+FFFF,所以他必須編譯成32位元(4個byte)的格式,如下所示:

V = 0x64321
Vx = V - 0x10000
= 0x54321
= 0101 0100 0011 0010 0001

Vh = 01 0101 0000 // Vx的高位部份的10 bits
Vl = 11 0010 0001 // Vx的低位部份的10 bits
w1 = 0xD800 //結果的前16位元初始值
w2 = 0xDC00 //結果的後16位元初始值

w1 = w1 | Vh
= 1101 1000 0000 0000
 |       01 0101 0000
= 1101 1001 0101 0000
= 0xD950

w2 = w2 | Vl
= 1101 1100 0000 0000
 |       11 0010 0001
= 1101 1111 0010 0001
= 0xDF21

所以這個字U+64321最後正確的UTF-16編碼應該是:

0xD950 0xDF21

而在小尾序中最后的编码应该是:

0x50D9 0x21DF

因為這個字超過U+FFFF所以無法用UCS-2的格式編碼。

16進制編碼範圍 UTF-16表示方法(二進制) 10進制碼範圍 字節數量
U+0000 - U+FFFF xxxx xxxx xxxx xxxx - yyyy yyyy yyyy yyyy 0-65535 2
U+10000 - U+10FFFF 1101 10yy yyyy yyyy - 1101 11xx xxxx xxxx 65536-1114111 4

UTF-16比起UTF-8,好處在於大部分字符都以固定長度的字節(2字節)儲存,但UTF-16卻無法相容於ASCII編碼。

UTF-16的編碼模式

UTF-16的大尾序和小尾序儲存形式都在用。一般來說,以Macintosh製作或儲存的文字使用大尾序格式,以MicrosoftLinux製作或儲存的文字使用小尾序格式。

為了弄清楚UTF-16文件的大小尾序,在UTF-16文件的開首,都會放置一個U+FEFF字符作為Byte Order Mark(UTF-16 LE以 FF FE 代表,UTF-16 BE以 FE FF 代表),以顯示這個文字檔案是以UTF-16編碼,其中U+FEFF字符在UNICODE中代表的意義是 ZERO WIDTH NO-BREAK SPACE,顧名思義,它是個沒有寬度也沒有斷字的空白。

以下的例子有四個字符:「朱」(U+6731)、半角逗號(U+002C)、「聿」(U+807F)、「𪚥」(U+2A6A5)。

使用UTF-16編碼的例子
編碼名稱 編碼次序 編碼
BOM , 𪚥
UTF-16 LE 小尾序,不含BOM 31 67 2C 00 7F 80 69 D8 A5 DE
UTF-16 BE 大尾序,不含BOM 67 31 00 2C 80 7F D8 69 DE A5
UTF-16 LE 小尾序,包含BOM FF FE 31 67 2C 00 7F 80 69 D8 A5 DE
UTF-16 BE 大尾序,包含BOM FE FF 67 31 00 2C 80 7F D8 69 DE A5

UTF-16與UCS-2的關係

UTF-16可看成是UCS-2的父集。在沒有輔助平面字符(surrogate code points)前,UTF-16與UCS-2所指的是同一的意思。但當引入輔助平面字符後,就稱為UTF-16了。現在若有軟件聲稱自己支援UCS-2編碼,那其實是暗指它不能支援在UTF-16中超過2位元組的字集。對於小於0x10000的UCS碼,UTF-16編碼就等於UCS碼。

Microsoft Windows操作系统内核对Unicode的支持

Windows操作系统内核中的字符表示为UTF-16小尾序,可以正确处理、显示以4字节存储的字符。但是Windows API实际上仅能正确处理UCS-2字符,即仅以2字节存储的,码位小于U+FFFF的Unicode字符。其根源是Microsoft C++语言把 wchar_t 数据类型定义为16比特的unsigned short,这就与一个 wchar_t 型变量对应一个宽字符、可以存储一个Unicode字符的规定相矛盾。相反,Linux平台的GCC编译器规定一个 wchar_t 是4字节长度,可以存储一个UTF-32字符,宁可浪费了很大的存储空间。下例运行于Windows平台的C++程序可说明此点:

// 此源文件在Windows平台上必须保存为Unicode格式(即UTF-16小尾)
// 因为包含的汉字“𪚥”,不能在简体中文版Windows默认的代码页936(即GBK)中表示
// 该汉字在UTF-16小尾序中用4个字节表示
// Windows操作系统能正确显示这样的在UTF-16需用4字节表示的字符
// 但是Windows API不能正确处理这样的在UTF-16需用4字节表示的字符,把它判定为2个UCS-2字符

#include <windows.h>
#include <stdio.h>

int main()
{
	const wchar_t lwc[] = L"𪚥";

	MessageBoxW(NULL, lwc, lwc, MB_OK);

	int i = wcslen(lwc);
	printf("%d\n", i);
	int j = lstrlenW(lwc);
	printf("%d\n", j);

	return 0;
}

Windows 9x系统的API仅支持ANSI字符集,只支持部分的UCS-2转换。1996年发布的Windows NT 4.0的API支持UCS-2。Windows 2000开始,Windows系统API开始支持UTF-16,并支持Surrogate Pair;但许多系统控件比如文本框和label等还不支持surrogate pair表示的字符,会显示成两个字符。Windows 7及更新的系统已经良好地支持了UTF-16,包括Surrogate Pair。

Windows API支持在UTF-16LE(wchar_t类型)与UTF-8(代码页CP_UTF8)之间的转码。例如:

#include <windows.h>
int main() {
	char a1[128], a2[128] = { "Hello" };
	wchar_t w = L'页';
	int n1, n2= 5;
	wchar_t w1[128];
	int m1 = 0;

	n1 = WideCharToMultiByte(CP_UTF8, 0, &w, 1, a1, 128, NULL, NULL);
	m1 = MultiByteToWideChar(CP_UTF8, 0, a2, n2, w1, 128);
}

参考文献

  1. ^ Code in Apache Xalan 2.7.0 which can fail on surrogate pairs. Apache Foundation. [2012-03-23]. (原始内容存档于2011-04-23). The code wrongly assumes it is safe to use substring on the input 
  2. ^ Python 2.6 decode of UTF16 does this on Linux, and it correctly handles surrogate pairs. All "CESU" decoders do it too, though they also mistranslate correct surrogate pairs into 2 characters

外部連結

  • Unicode Technical Note #12: UTF-16 for Processing (页面存档备份,存于互联网档案馆
  • A very short algorithm for determining the surrogate pair for any codepoint(页面存档备份,存于互联网档案馆
  • Unicode FAQ: What is the difference between UCS-2 and UTF-16? (页面存档备份,存于互联网档案馆
  • Unicode Character Name Index (页面存档备份,存于互联网档案馆
  • RFC 2781: UTF-16, an encoding of ISO 10646
  • java.lang.String documentation, discussing surrogate handling (页面存档备份,存于互联网档案馆
Unicode
码位
字符
通用字元集字元英语Universal Character Set characters
列表
處理
演算法
統一碼編碼比較英语Comparison of Unicode encodings
組合字符
使用
相關標準
相關主題
 
Unicode收录的文字
收录文字
現代文字
古代文字
標記文字
符號
早期電信
  • 電報電碼英语Telegraph code
    • 庫克與惠斯通英语Cooke and Wheatstone telegraph
    • 摩斯
      • 非拉丁字母英语Morse code for non-Latin alphabets
      • 日文英语Wabun code
      • 中文
      • 西里爾字母英语Russian Morse code
      • 韓文英语SKATS
    • 博多與莫瑞
  • Fieldata英语Fieldata
  • ASCII
  • BCDIC英语BCD (character encoding)
  • 電傳文訊英语Teletex電傳視訊英语Videotex電視資訊
    • T.51/ISO/IEC 6937英语T.51/ISO/IEC 6937
    • ITU T.61英语ITU T.61
    • ITU T.101英语Videotex character set
    • 世界系統電傳文訊英语World System Teletext
      • 字元集英语Teletext character set
ISO/IEC 8859
書目
  • MARC-8英语MARC-8
  • ISO 5426英语ISO 5426
  • ISO 5427英语ISO 5427
  • ISO 5428英语ISO 5428
  • ISO 6438
  • ISO 6862英语ISO 6862
國家標準
ISO/IEC 2022
macOS代码页
  • 亞美尼亞文英语Mac OS Armenian
  • 阿拉伯文
  • 巴倫支西里爾字母英语Mac OS Barents Cyrillic
  • 凱爾特語族英语Mac OS Celtic
  • 中歐語言
  • 克羅埃西亞文英语Mac OS Croatian encoding
  • 西里爾字母英语Mac OS Cyrillic encoding
  • 梵文
  • 波斯文英语MacFarsi encoding
  • 字體X英语Macintosh Font X encoding
  • 蓋爾文英语Mac OS Gaelic
  • 喬治亞文英语Mac OS Georgian
  • 希臘文英语MacGreek encoding
  • 古吉拉特文英语Mac OS Gujarati
  • 古木基文英语Mac OS Gurmukhi
  • 希伯來文英语Mac OS Hebrew
  • 冰島文英语Mac OS Icelandic encoding
  • 因紐特文英语Mac OS Inuit
  • 鍵盤英语Mac OS Keyboard encoding
  • 拉丁文英语Macintosh Latin encoding
  • 馬爾他文/世界文英语Mac OS Maltese/Esperanto encoding
  • 歐甘字母英语Mac OS Ogham
  • 羅曼語族
  • 羅馬尼亞文英语Mac OS Romanian encoding
  • 薩米文英语Mac OS Sámi
  • 土耳其文英语Mac OS Turkish encoding
  • 土耳其西里爾字母英语Mac OS Turkic Cyrillic
  • 烏克蘭文英语Mac OS Ukrainian encoding
  • VT100英语VT100 encoding
DOS代碼頁
  • 437
  • 668英语Code page 668
  • 708英语Code page 708
  • 720英语Code page 720
  • 737英语Code page 737
  • 770英语Code page 770
  • 773英语Code page 773
  • 775英语Code page 775
  • 776英语Code page 776
  • 777英语Code page 777
  • 778英语Code page 778
  • 850英语Code page 850
  • 851英语Code page 851
  • 852英语Code page 852
  • 853英语Code page 853
  • 855英语Code page 855
  • 856英语Code page 856
  • 857英语Code page 857
  • 858英语Code page 858
  • 859英语Code page 859
  • 860英语Code page 860
  • 861英语Code page 861
  • 862英语Code page 862
  • 863英语Code page 863
  • 864英语Code page 864
  • 865英语Code page 865
  • 866英语Code page 866
  • 867英语Code page 867
  • 868英语Code page 868
  • 869英语Code page 869
  • 897英语Code page 897
  • 899英语Code page 899
  • 903英语Code page 903
  • 904英语Code page 904
  • 932英语Code page 932 (IBM)
  • 936英语Code page 936 (IBM)
  • 942英语Code page 942
  • 949英语Code page 949 (IBM)
  • 950
  • 951英语Code page 951
  • 1040英语Code page 1040
  • 1042英语Code page 1042
  • 1043英语Code page 1043
  • 1046英语Code page 1046
  • 1098英语Code page 1098
  • 1115英语Code page 1115
  • 1116英语Code page 1116
  • 1117英语Code page 1117
  • 1118英语Code page 1118
  • 1127英语Code page 1127
  • 3846英语Code page 3846
  • ABICOMP英语ABICOMP character set
  • CS Indic英语CS Indic character set
  • CSX Indic英语CSX Indic character set
  • CSX+ Indic英语CSX+ Indic character set
  • CWI-2英语CWI-2
  • 伊朗系統英语Iran System encoding
  • 卡梅尼茨英语Kamenický encoding
  • 馬索維亞英语Mazovia encoding
  • MIK英语MIK (character set)
IBM AIX代碼頁
  • 895英语Code page 895
  • 896英语Code page 896
  • 912英语Code page 912
  • 915英语Code page 915
  • 921英语Code page 921
  • 922英语Code page 922
  • 1006英语Code page 1006
  • 1008英语Code page 1008
  • 1009英语Code page 1009
  • 1010英语Code page 1010
  • 1012英语Code page 1012
  • 1013英语Code page 1013
  • 1014英语Code page 1014
  • 1015英语Code page 1015
  • 1016英语Code page 1016
  • 1017英语Code page 1017
  • 1018英语Code page 1018
  • 1019英语Code page 1019
  • 1124英语Code page 1124
  • 1133英语Code page 1133
Microsoft Windows代碼頁英语Windows code page
  • CER-GS英语CER-GS
  • 932英语Code page 932 (Microsoft Windows)
  • 936
  • 950
  • 1169英语Code page 1169
  • Extended Latin-8英语Extended Latin-8
  • 1250英语Windows-1250
  • 1251英语Windows-1251
  • 1252
  • 1253英语Windows-1253
  • 1254英语Windows-1254
  • 1255英语Windows-1255
  • 1256英语Windows-1256
  • 1257英语Windows-1257
  • 1258英语Windows-1258
  • 1270英语Windows-1270
  • 西里爾字母+芬蘭文英语Windows Cyrillic + Finnish
  • 西里爾字母+法文英语Windows Cyrillic + French
  • 西里爾字母+德文英语Windows Cyrillic + German
  • 希臘語變音符號英语Windows Polytonic Greek
EBCDIC代碼頁
  • 37英语Code page 37
  • EBCDIC中的日文英语Japanese language in EBCDIC
  • DKOI英语DKOI
DEC終端機(VTx英语VT220
  • MCS英语Multinational Character Set
  • NRCS英语National Replacement Character Set
    • 加拿大法文英语Code page 1020
    • 瑞士文英语Code page 1021
    • 西班牙文英语Code page 1023
    • 英國英文英语Code page 1101
    • 荷蘭文英语Code page 1102
    • 芬蘭文英语Code page 1103
    • 法文英语Code page 1104
    • 挪威文/丹麥文英语Code page 1105
    • 瑞典文英语Code page 1106
    • 挪威文/丹麥文(替代)英语Code page 1107
  • 8位元希臘文英语Code page 1287
  • 8位元土耳其文英语Code page 1288
  • SI 960英语SI 960
  • 希伯來文英语DEC Hebrew
  • 特殊圖形英语DEC Special Graphics
  • 技術英语DEC Technical Character Set
特定平臺
  • 1057英语Code page 1057
  • Acorn英语RISC OS character set
  • Adobe標準英语PostScript Standard Encoding
  • Adobe Latin 1英语PostScript Latin 1 Encoding
  • Amstrad CPC英语Amstrad CPC character set
  • Apple II英语Apple II character set
  • 雅達利資訊交換標準碼英语ATASCII
  • 雅達利ST英语Atari ST character set
  • BICS英语Bitstream International Character Set
  • 卡西歐計算機英语Casio calculator character sets
  • CDC英语CDC display code
  • Compucolor II英语Compucolor II character set
  • CP/M+英语Amstrad CP/M Plus character set
  • DEC RADIX 50英语DEC RADIX 50
  • DEC MCS英语Multinational Character Set/NRCS英语National Replacement Character Set
  • DG國際英语DG International
  • Fieldata英语Fieldata
  • GEM英语GEM character set
  • GSM 03.38英语GSM 03.38
  • HP Roman英语HP Roman
  • HP FOCAL英语FOCAL character set
  • HP RPL英语RPL character set
  • SQUOZE英语SQUOZE
  • LICS英语Lotus International Character Set
  • LMBCS英语Lotus Multi-Byte Character Set
  • MSX英语MSX character set
  • NEC APC英语NEC APC character set
  • NeXT英语NeXT character set
  • PETSCII英语PETSCII
  • SEGA SC-3000英语Sega SC-3000 character set
  • 夏普計算機英语Sharp pocket computer character sets
  • 夏普MZ英语Sharp MZ character set
  • 辛克萊QL英语Sinclair QL character set
  • 符號
  • 電傳文訊英语Teletext character set
  • 德州儀器計算機英语TI calculator character sets
  • TRS-80英语TRS-80 character set
  • 文圖拉國際英语Ventura International
  • WISCII英语Wang International Standard Code for Information Interchange
  • XCCS英语Xerox Character Code Standard
  • ZX80英语ZX80 character set
  • ZX81英语ZX81 character set
  • ZX Spectrum英语ZX Spectrum character set
Unicode通用字符集
TeX排版系統
  • 科克英语Cork encoding
  • LY1英语LY1 encoding
  • OML英语OML encoding
  • OMS英语OMS encoding
  • OT1英语OT1 encoding
其他代碼頁
  • ABICOMP英语ABICOMP character set
  • ASMO 449英语ASMO 449
  • 大五碼
  • APL符號數位編碼英语Digital encoding of APL symbols
    • ISO-IR-68英语ISO-IR-68
  • ARIB STD-B24
  • HZ英语HZ (character encoding)
  • IEC-P27-1英语IEC-P27-1
  • INIS
    • 7位元英语INIS character set
    • INIS-8英语8位元
  • ISO-IR-169英语ISO-IR-169
  • ISO 2033英语ISO 2033
  • KOI
    • -R
    • -RU英语KOI8-RU
    • -U
  • 今昔文字鏡
  • SEASCII英语Stanford Extended ASCII
  • Stanford/ITS英语Stanford/ITS character set
  • TRON英语TRON (encoding)
  • 統合韓文代碼英语Unified Hangul Code
控制字符
相關條目
分类 字元集