人小鬼不大

导航

 

 

1、ANSI 多字节编码

  最早时计算机只支持英文字符,都是用 ASCII(American Standard Code for Information Interchange,美国标准信息交换代码)编码,一个字母或符号只需要一个字节存储。微软针对本地化字符编码采用的就是用 ANSI(American National Standards Institute,美国国家标准学会)多字节编码方式,系统里的英文和符号就使用单字节的 ASCII(0x00~0x7f),而对于汉字之类的本地化字符编码,就采用 0x80~0xFF 范围内的多个字节来表示,这样既能兼容 ASCII ,又能正常使用本地化语言文字。

支持的汉字编码:http://www.fmddlmyy.cn/text24.html

2、Unicode 系列编码

  ANSI 多字节编码解决了各种语言文字的本地化使用问题,也有它自己的缺陷:各地制定的编码标准只对自己的语言文字有效,而不同语言文字的编码都是冲突的,因为大家都用 0x80~0xFF 范围字节表示自己的语言文字,而不考虑别的语言文字如何编码,冲突在所难免。将一种编码放到另一种编码的系统中会出现乱码,因此国际组织制定了 Unicode 编码,这种字符编码是对全球语言统一分配编码区间,各种语言字符互相不冲突,都可以兼容使用。

  Unicode 编码系统,可分为编码方式和实现方式两个层次。对于国际组织发布的 Unicode 编码标准,对应的就是编码方式,最常用的是 UCS-2(Universal Character Set 2),采用两字节编码一个字符。也有四字节编码方式 UCS-4。在编码实现的过程中,有些考虑兼容旧的单字节 ASCII 编码,有些不考虑兼容性;有些考虑双字节中哪个字节放在前面,哪个字节放在后面的问题,即 BOM(Byte Order Mark,字节顺序标记)的作用。因此诞生了多种国际码的实现方式,统称为 Unicode 转换格式(Unicode Transformation Format,UTF)。

Unicode 转换格式说明
UTF-8 灵活的变长编码,对于 ASCII 使用一个字节编码,其他本地化语言文字用多个字节编码,最长可以到 6 个字节编码一个字符。对于汉字,通常是 3 个字节表示一个汉字。这是 Unix/Linux 系统默认的字符编码。
UTF-16 兼容 UCS-2,一般都是两字节表示一个字符,对于超出两字节的国际码字符,使用一对两字节来表示。在存储时,按两个字节的排布顺 序,可以分为 UTF-16LE(Little Endian,小端字节序)和UTF-16BE(Big Endian,大端字节序),微软所说的 Unicode 默认就是 UTF-16LE。
UTF-32 同 UCS-4,因为用四个字节表示一个字符,所以不需要考虑扩展了。这种编码方式简单,但也特别浪费空间,所以应用很少。在存储时也分为 UTF-32BE 和 UTF-32LE,因为用得少,所以不用太关心这种编码格式。

  Unicode通常用两个字节表示一个字符,原有的英文编码从单字节变成双字节,只需要把高字节全部填为0就可以。

2.1 UTF-8以字节为单位对Unicode进行编码

从Unicode到UTF-8的编码方式如下:

Unicode编码(十六进制)     UTF-8 字节流(二进制)
000000-00007F          0xxxxxxx
000080-0007FF        110xxxxx 10xxxxxx
000800-00FFFF      1110xxxx 10xxxxxx 10xxxxxx
010000-10FFFF    11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

  UTF-8的特点是对不同范围的字符使用不同长度的编码。对于0x00-0x7F之间的字符,UTF-8编码与ASCII编码完全相同。UTF-8编码的最大长度是4个字节。从上表可以看出,4字节模板有21个x,即可以容纳21位二进制数字。Unicode的最大码位0x10FFFF也只有21位。

  编码转换方式如:“汉”字的Unicode编码是0x6C49。0x6C49在0x0800-0xFFFF之间,使用3字节模板:1110xxxx 10xxxxxx 10xxxxxx。将0x6C49写成二进制是:0110 1100 0100 1001, 用这个比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。该示例中模板含有16个x,0x6C49转换为二进制刚好16位,因此不需要补0。若位数不足,则在前面补0。

2.2 UTF-16编码

UTF-16编码以16位无符号整数为单位。我们把Unicode编码记作U。编码规则如下:
  如果U<0x10000,U的UTF-16编码就是U对应的16位无符号整数(为书写简便,下文将16位无符号整数记作WORD)。
  如果U≥0x10000,我们先计算U'=U-0x10000,然后将U'写成二进制形式:yyyy yyyy yyxx xxxx xxxx,U的UTF-16编码(二进制)就是:110110yyyyyyyyyy 110111xxxxxxxxxx。
  可见,第一个WORD的取值范围(二进制)是11011000 00000000到11011011 11111111,即0xD800-0xDBFF。第二个WORD的取值范围(二进制)是11011100 00000000到11011111 11111111,即0xDC00-0xDFFF。

  U'可以被写成20个二进制位的原因是:Unicode的最大码位是0x10FFFF,减去0x10000后,U'的最大值是0xFFFFF,所以可以用20个二进制位表示。

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

2.2.1 代理区

  为了将一个WORD的UTF-16编码与两个WORD的UTF-16编码区分开来,Unicode编码的设计者将0xD800-0xDFFF保留下来,并称为代理区(Surrogate):
D800-DB7F
High Surrogates
高位替代
DB80-DBFF
High Private Use Surrogates
高位专用替代
DC00-DFFF
Low Surrogates
低位替代

高位替代就是指这个范围的码位是两个WORD的UTF-16编码的第一个WORD。低位替代就是指这个范围的码位是两个WORD的UTF-16编码的第二个WORD。

2.2.2 计算Unicode编码的范围

  如果一个字符的UTF-16编码的第一个WORD在0xDB80到0xDBFF之间,那么它的Unicode编码在什么范围内?
  由上图可知,第二个WORD的范围是0xDC00-0xDFFF,所以这个字符的UTF-16编码范围应该是0xDB80 0xDC00到0xDBFF 0xDFFF。将这个范围写成二进制:1101101110000000 11011100 00000000 - 1101101111111111 1101111111111111
按照编码的相反步骤,每16位二进制去掉前6位,取出高低WORD的后10位,并拼在一起,得到
  1110 0000 0000 0000 0000 - 1111 1111 1111 1111 1111
即0xE0000-0xFFFFF,按照编码的相反步骤再加上0x10000,得到0xF0000-0x10FFFF。这就是UTF-16编码的第一个WORD在0xdb80到0xDBFF之间的Unicode编码范围,即平面15和平面16。因为Unicode标准将平面15和平面16都作为专用区,所以0xDB80到0xDBFF之间的保留码位被称作高位专用替代。 

2.3 UTF-32编码

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

  字节序有两种,分别是“大端”(Big Endian, BE)和“小端”(Little Endian, LE)。根据字节序的不同,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
30 DC 43 D8
D8 43 DC 30
30 0C 02 00
00 02 0C 30

根据UTF-16计算结果,根据大小端字节序显示。UTF32需要4个字节,不够就在前面补0。

 

相关常见的问题解答:http://www.unicode.org/faq/utf_bom.html

posted on 2020-01-21 17:23  人小鬼不大  阅读(379)  评论(0编辑  收藏  举报