《字符集与字符编码》
https://www.yuque.com/saopanda/saopanda/rt7gtg
字符集 是存放字符的集合
字符编码 是用某个数字来表示某个字符的规则,因为计算机上只能存储二进制数字
ASCII编码
- 标准 ASCII码
每个字符占一个字节,使用后 7位,首位固定为0,最多可容纳128个字符,共128个字符(ASCII的字符集)
- 扩展 ASCII码(高ASCII)
启用了第8位,补充了附加的128个字符,包括特殊字符、外来语、图形符号等。
可通过 ASCII码表,查找 数字与字符的对应关系
标准 ASCII中,最高位(第7位)作为奇偶校验位。没懂怎么实现的
GBK编码
兼容ASCII码,0~127与ASCII码一致,不兼容ASCII扩展码。汉字占用双字节
- GB2312
当两个大于127的字符连接在一起时,才会被识别成一个汉字,容量小 7000多个简体汉字
- GBK
大于127的字符出现时,代表汉字开始,与之后一个字符组合识别为一个汉字。由于第二个字符不受限,容量较大,同时兼容GB2312,新增2w多个汉字与字符,包括繁体字
- GB18030
在GBK的基础上 增加了一些字符,包括少数名族字符、特殊字符等
Unicode
统一码,万国码,是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案,它为每种语言每个符号 都设定了统一且唯一的数字。Unicode整个编码系统包含两部分,编码方式和实现方式
编码方式
编码方式指:Unicode的字符集与数字的对应。既然只是数字与字符的对应关系,为什么不简单点直接一一向下排列对应,还要再弄一个编码方式 UCS(Universal Character Set)呢?
分组、划区、专用区、代理区等,便于管理、实现其他功能
Unicode的字符集简写为 UCS,早期分为 UCS-2、UCS-4,分别占2字节和4字节。
UCS-4 的组成:
- 首字节,首位固定为 0,7位可用,分为128个 组(group)
- 第二字节,全部可用,又分为 256个平面(plane)
- 第三字节,继续分为 256行(row)
- 第四字节,有了 256个码位(cell)
- 第三字节,继续分为 256行(row)
- 第二字节,全部可用,又分为 256个平面(plane)
UCS-4 的 组和平面都为0时,称作BMP。去掉这俩个0字节,即为 UCS-2
Unicode计划使用 17个平面,平面0到16,也就是0-0x10FFFF, (2^16) * 17 = 1114112个码位。
在Unicode5.0中,定义了238605个码位:
平面15、16有两个专用区 655342,平面 0有 6400个码位的专用区,2048个码位的代理区(供 utf-16使用)
所以实际定义的字符有 238605-655342-6400-2408=99089个,其中包括 71226个汉字,平面0上27973个汉字,平面2上的43253个都是汉字。
Unicode 兼容 ASCII,从数字0到127表示的字符与ASCII一致
实现:UTF-8编码
以字节为单位对Unicode进行编码,不同范围的字符长度不同
为什么UTF-8编码下的汉字占 3 个字节?如下表,汉字的码点范围在3字节长度
字节长度 | 格式 | 实际编码位 | 码点范围 | |
---|---|---|---|---|
1 | 0xxxxxxx | 7 | 0 ~ 127 | ASCII |
2 | 110xxxxx 10xxxxxx | 11 | 128 ~ 2047 | |
3 | 1110xxxx 10xxxxxx 10xxxxxx | 16 | 2048 ~ 65535 | 汉字所在的范围 |
4 | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx | 21 | 65536 ~ 2097151 |
字节格式
- 以 0 开头表示为单字节字符
- 110 表示双字节字符开始,1110表示三字节字符开始,11110表示四字节字符开始
- 10开头表示属于某个字符的一部分
UTF-8 四字节编码,有21位二进制可用,Unicode计划使用的17个面,其最大值0x10FFFF,换算成二进制也是21位,所以UTF-8最大表示范围还比 Unicode大不少
例:“汉” Unicode为 0x6C49,27721,二进制 0110 1100 0100 1001,属于三子节编码
尾部对齐替换 “1110xxxx 10xxxxxx 10xxxxxx” 中的 “x”,位数不足的头部补 0。替换后,“汉”在UTF-8编码下的二进制表达如下:
11100110 10110001 10001001
实现:UTF-16编码
UTF-16使用两个字节为单位,也就是16个二进制位。
当码点小于 0x10000,65536,也就是16位二进制足够表达时,直接使用码点原始值。
超出16位的部分如何编码?
码点超过 0xFFFF的字符,就把两个UTF-16单位连接起来,组成一个字符,占4字节。
其中每个单位的前6位固定,用于标识双单位字符。110110表示该字符的开始,110111表示该字符结束。
110110xxxxxxxxxx 110111yyyyyyyyyy
然后用该字符的(码点值 - 0x10000),获得的新值二进制有20位,前10位填入x,后10位填入 y 即可
Unicode最大值 0x10FFFF,UTF-16能放的下吗?
一个单位的字符有16位,可放 (0xFFFF + 1)个数
两个单位的字符有20位(10个x10个y),可放(0xFFFFF + 1)个数,一共可放 0x110000个
刚好也是Unicode可容纳的数量(0x10FFFF + 1)= 0x110000
单单位 与 双单位 的UTF-16字符如何互不干扰?
第一个标识 110110xxxxxxxxxx 范围是 0xD800-0xDBFF
第二个标识 110111yyyyyyyyyy 范围是 0xDC00-0xDFFF
Unicode将这些范围设成了代理区,仅供两个单位的UTF-16字符使用,所以互不影响
D800-DB7F | 高位替代 | 标识第一个单位 |
---|---|---|
DB80-DBFF | 高位专用替代 | 也标识第一个单位 |
DC00-DFFF | 低位替代 | 标识第二个单位 |
高位专用替代是啥?
把该范围的UTF-16编码字符反推到 Unicode,其范围在Unicode的专用区(平面15、16),所以此代理范围也被称作专用替代