Unicode 编码理解

时间:2025-03-15 07:22:08

    Unicode(统一码、万国码、单一码)于1990年开始研发,1994年正式公布,是计算机领域里一项业界标准,包括字符集,编码方案等。Unicode是为了解决传统字符编码方案的局限而产生的,为每种语言中的每个字符都设定了统一唯一的二进制编码,以实现跨语言、跨平台进行文本转换、处理的要求。

    计算机在设计时采用8个比特(bit)作为一个字节(byte),所以一个字节最多能表示256个字符,早期对于使用英文的西方国家来说,一个字节可以存储大小写英文字母、数学和一些符号,因此使用一个字节来制作码表(ASCII)。后来计算机传到了其他的国家,很多国家都是使用自己的语言,比如中文、日文、韩文…语言复杂了,为了解决这个问题,每个国家制定自己的码表,中国在1980年便制定了GB2312汉字编码字符集,汉字比英文多很多,一个字节明显不够用,所有就使用2个字节来编码。然而不同国家所定义的字符编码虽然可以使用,但是在不同的国家间却经常出现不兼容的情况。如果电脑想处理多语言环境(使用中文或其他语言)可能存在无法同时支持多语言环境。

    为了统一所有文字的编码,产生了Unicode,把所有语言的都统一到一套编码里,这样就不会乱码了。

    在表示Unicode字符时,通常会用U+然后紧跟一组16进制的数字表示一个字符,在基本多文种平面(第零平面)Basic MultilingualPlane(BMP)里所有的字符都使用4位16进制表示。编码从U+0000到U+FFFF,共支持6万多个字符,在BMP以外的字符则需要使用5位或者6位16进制来表示。

    目前Unicode字符分为17组编排,0x0000至0x10FFFF,每组称为平面(Plane),每个面拥有65536个码位,共1114112个。

    Unicode就像一张表,包所有的字符都编写到表中,每一个字符对应一个数字,称为码点(code point),这个数字一般不直接使用,通过不同的编码方式来使用。

    UTF-8、UTF-16、UTF-32就是将数字转换到程序数据的编码方案。UTF是“UnicodeTransformation Format”的缩写,可以翻译成Unicode字符集转换格式,即怎样将Unicode定义的数字转换成程序数据。


    UTF-8

    UTF-8是以字节位单位对Unicode编码,第0-127位字符使用1个字节来表示,和ASCII编码相同,从128号开始的字符使用2、3、4位字节来表,UTF-8又被称为可变长编码。

    UTF-8编码中,使用的是变成的字节序列表示字符,字符对应的代码点(code point)可能使用的是1-4个字节,这样一个字节就是一个代码单元。一个代码点(code point)可能由1-4个代码单元(code unit)组成。

十进制

Unicode编码

UTF-8字节流

0-127

0x000000-0x00007F

0xxxxxxx(7位)

128-2047

0x000080-0x0007FF

110xxxxx 10xxxxxx(11位)

2048-65535

0x000800-0x00FFFF

1110xxxx 10xxxxxx 10xxxxxx(16位)

65536-1114111

0x010000-0x10FFFF

11110xxx 10xxxxxx 10xxxxxx 10xxxxxx(21位)

     比如:“汉”在Unicode中的编码为0x6C49,在表格中的第三行,使用模板为:1110xxxx 10xxxxxx10xxxxxx。将0x6C49转换成二进制:0110 1100 0100 1001,将模板中的x依次替换11100110 10110001 10001001,即E6 B1 89


    UTF-16

    UTF-16也是可变长度编码,使用2个或者4个字节来存储字符,但是会浪费存储空间。

    UTF-16编码中,字符对应的代码点(code point)可能使用的是2或4个字节,因此2个字节就是一个代码单元(code unit),一个代码点(codepoint)可由1个或者2个代码单元(code unit)组成。

十进制

Unicode编码

UTF-16字节流

0-65535

0x000000-0x00FFFF

xxxxxxxx xxxxxxxx(16位)

65536-1114111

0x010000-0x10FFFF

110110yy yyyyyyyy 110111xx xxxxxxxx(20位)

    平面0有一个专用区:0xE000-0xF8FF,有6400个码位。平面0的0xD800-0xDFFF,共2048个码位,是一个被称作代理区(Surrogate)的特殊区域。代理区的目的用两个UTF-16字符表示BMP以外的字符。所有大于0x00FFFF的码需要使用代理区的码点。

    为了将一个16位无符号整数的UTF-16编码与二个16位无符号整数的UTF-16编码区分开来,Unicode编码的设计者将0xD800-0xDFFF保留下来,并称为代理区(Surrogate):

十进制

Unicode编码

说明

说明

55296-56191

0xD800-0xDB7F(896个)

High Surrogates

高位替代

56192-56913

0xDB80-0xDBFF(128个)

High Private Use Surrogates

高位专用替代

56320-57343

0xDC00-0xDFFF(1024个)

Low Surrogates

低位替代

     增补的16个平面(第2平面-第17平面),范围为:0x010000-0x10FFFF,需要使用2个代理码元表示,第一个码元为0xD800-0xDBFF(高位)范围是:11011000 0000000011011011 11111111,第二个码元为0xDC00-0xDFFF(低位)范围是:11011100 0000000011011111 11111111

    目前Unicode最大的码位是0x10FFFF,减去0x010000后最大值为0xFFFFF,完全可以用20位来表示。

    把Unicode编码记作U,如果U≥0x10000,我们先计算U'=U-0x10000,然后将U'写成二进制形式:yyyy yyyy yyxx xxxx xxxx,U的UTF-16编码(二进制)就是:110110yyyyyyyyyy110111xxxxxxxxxx

    比如:Unicode编码0x20C30,减去0x10000后,得到0x10C30,写成二进制是:0001 0000 1100 0011 0000。用前10位依次替代模板中的y,用后10位依次替代模板中的x,就得到:1101100001000011 1101110000110000,即0xD8430xDC30


    UTF-32

    UTF-32编码以32位无符号整数为单位。Unicode的UTF-32编码就是其对应的32位无符号整数。

    UTF-32编码,一个代码点对应4个字节,因此4个字节就是一个代码单元(codeunit)。

十进制

Unicode编码

UTF-32字节流

0-111411

0x000000-0x10FFFF

xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx (32位)

    比如:编码0x6C49使用UTF-32编码其结果为:0x00006C49。


    字节序

    字节序有两种,分别是大端(Big Endian, BE)和小段(Little Endian, LE)。根据字节序的不同,UTF-16实现为UTF-16BE和UTF-16LE,UTF-32实现为UTF-32BE和UTF-32LE。

    根据字节序的不同,UTF-16可被实现为UTF-16LE或UTF-16BE,UTF-32可被实现为UTF-32LE或UTF-32BE。

Unicode编码

UTF-16LE

UTF-16BE

UTF32-LE

UTF32-BE

0x006C49

49 6C

6C 49

49 6C 00 00

00 00 6C 49

0x020C30

43 D8 30 DC

D8 43 DC 30

30 0C 02 00

00 02 0C 30

     Unicode标准建议用BOM(Byte Order Mark)来区分字节序,即在传输字节流前,先传输被作为BOM的字符“零宽无中断空格”。这个字符的编码是FEFF,而反过来的FFFE(UTF-16)和FFFE0000(UTF-32)在Unicode中都是未定义的码位,不应该出现在实际传输中。

    UTF编码的BOM

UTF编码

Byte Order Mark (BOM)

UTF-8 without BOM

 无

UTF-8 with BOM

EF BB BF

UTF-16LE

FF FE

UTF-16BE

FE FF

UTF-32LE

FF FE 00 00

UTF-32BE

00 00 FE FF