unicode是一个字符集,也称为unicode编码,为每一个字符分配了一个ID,这个ID称为码点
Unicode的编码空间从U+0000到U+10FFFF
,共有1,112,064个码位(code point)可用来映射字符。Unicode的编码空间可以划分为17个平面(plane),每个平面包含216(65,536)个码位。17个平面的码位可表示为从U+xx0000到U+xxFFFF
,共计17个平面。第一个平面称为基本多语言平面(Basic Multilingual Plane, BMP),或称第零平面(Plane 0),其他平面称为辅助平面(Supplementary Planes)
。基本多语言平面内,从U+D800到U+DFFF
之间的码位区段是永久保留不映射到Unicode字符。UTF-16就利用保留下来的0xD800-0xDFFF
区段的码位来对辅助平面的字符的码位进行编码
UTF-16(16 bit Unicode Transformation Format)即16位的Unicode转换格式
,以16位即双字节为编码单元
UTF-16的编码对象就是unicode
我们常用到的字符都在unicode的第一个平面,也就是基本多语言平面(Basic Multilingual Plane, BMP)
,范围是0x0000-0xFFFF
。
UTF-16以两个字节为一个编码单位,范围是 0x0000 - 0xFFFF
。我们称为码元
当我们使用的字符unicode码点在 0x0000 - 0xFFFF
的时候
utf-16的编码和unicode的编码是一一对应的
比如 “我
”的码点是 6211
, 在多语言平面内,所以UTF-16编码也是 6211
码点范围 0x10000 - 0x10FFFF
的字符已经无法使用1个编码单位来标识,所以此时需要两个码元
比如这个字符的码点为 U+1F602
将码点范围左移 0x10000,此时码点范围是 0x0 - 0xFFFFF
, 为什么要移这一下子呢,因为0x10FFFF有21位,左移完只有20位,更好做拆分
将的码点同样进行左移
0x1F602 - 0x10000 = 0xf602
展开为20位,并分为两组,10位一组
0000111101 1000000010
将这组数据放入两个码元中(一个编码单位为两字节(16位)),其余补0
xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx # 两个码元
xxxxxx0000111101 xxxxxx1000000010 # 填充
0000000000111101 0000001000000010 # 补0
0x3D 0x202
得到第一个码元或称作高位代理(high surrogate)
得到第二个码元或称作低位代理(low surrogate)
现在一个码元的范围是 0 - 0x3FF(10位bit最高可表示0x3FF)
在多语言平面中,从U+D800到U+DFFF
之间的码位区段是永久保留不映射到Unicode字符,其大小为
0xDFFF - 0xD800 = 0x7FF
而一个码元的范围在 0x3FF, 所以将该码元移动到该区域
高位代理移动
0x3D + 0xD800 = 0xD83D
地位代理移动
高位代理占用了0x3FF的空间,所以地位代理要从 0xD800 + 0x3FF + 1
的地方开始移动
0xDC00 + 0x202 = 0xDE02
所以的最终编码就是 0xD8 0x3D 0xDE 0x02
这里以notepad++编辑器举例(其他编辑器也有可能有这个问题)
这里的Big Endian为大端序,另一个就是小端序了,如果你想看到正确的显示效果那么就选择大端序
,使用二进制编辑器打开时会发现文件开头有 FE FF
,这是BOM,忽略即可,从后面开始看
详细可以参考: https://blog.csdn.net/qq_56313338/article/details/133788268