本文作者: jsweibo
本文链接: https://jsweibo.github.io/2019/03/22/%E4%BB%80%E4%B9%88%E6%98%AFUTF-16/
摘要
本文主要讲述了:
- 什么是 UTF-16
- 编码规则
- 解码规则
正文
什么是 UTF-16
UTF-16 是一种变宽的 Unicode 字符编码方案。它使用 2 或 4 个字节编码 Unicode 字符。
编码规则
Unicode Number Range | UTF-16BE | UTF-16LE |
---|---|---|
U+0000 -> U+D7FF | 0000 -> D7FF | 0000 -> FFD7 |
U+D800 -> U+DFFF | 无编码区 | 无编码区 |
U+E000 -> U+FFFF | E000 -> FFFF | 00E0 -> FFFF |
U+10000 -> U+10FFFF | 代理对编码法 | 代理对编码法 |
代理对编码法:
- 将十六进制的 Unicode 码点与
0x10000
做差。 - 将差换算为 20 位的二进制。
- 将 20 位二进制拆分为高 10 位和低 10 位。
- 将高 10 位与
0xD800
做和。 - 将低 10 位与
0xDC00
做和。 - 两个和按照 BE 排列,就是 UTF-16 的十六进制 BE 编码。
- 两个和按照 LE 排列,就是 UTF-16 的十六进制 LE 编码。
示例:将eng
进行 UTF-16 编码。
e
的 Unicode 码点是U+0065
。U+0065
处在U+0000 -> U+D7FF
区间,因此 UTF-16BE 编码就是 Unicode 码点。e
的十六进制 UTF-16BE 编码是00 65
,十六进制 UTF-16LE 编码是65 00
。n
的 Unicode 码点是U+006E
。U+006E
处在U+0000 -> U+D7FF
区间,因此 UTF-16BE 编码就是 Unicode 码点。n
的十六进制 UTF-16BE 编码是00 6E
,十六进制 UTF-16LE 编码是6E 00
。g
的 Unicode 码点是U+0067
。U+0067
处在U+0000 -> U+D7FF
区间,因此 UTF-16BE 编码就是 Unicode 码点。g
的十六进制 UTF-16BE 编码是00 67
,十六进制 UTF-16LE 编码是67 00
。综上所述,
eng
的十六进制 UTF-16BE 编码是00 65 00 6E 00 67
,十六进制 UTF-16LE 编码是65 00 6E 00 67 00
。
示例:将中文
进行 UTF-16 编码。
中
的 Unicode 码点是U+4E2D
。U+4E2D
处在U+0000 -> U+D7FF
区间,因此 UTF-16BE 编码就是 Unicode 码点。中
的十六进制 UTF-16BE 编码是4E 2D
,十六进制 UTF-16LE 编码是2D 4E
。文
的 Unicode 码点是U+6587
。U+6587
处在U+0000 -> U+D7FF
区间,因此 UTF-16BE 编码就是 Unicode 码点。文
的十六进制 UTF-16BE 编码是65 87
,十六进制 UTF-16LE 编码是87 65
。综上所述,
中文
的十六进制 UTF-16BE 编码是4E 2D 65 87
,十六进制 UTF-16LE 编码是2D 4E 87 65
。
示例:将U+10000
进行 UTF-16 编码。
U+10000
处在U+10000 -> U+10FFFF
区间,因此采用代理对编码法。0x10000
与0x10000
做差,得到0x00000
。0x00000
换算为二进制,得到0000 0000 0000 0000 0000
。将
0000 0000 0000 0000 0000
的高 10 位和低 10 位拆分,得到0000 0000 00
和00 0000 0000
。高 10 位与
0xD800
做和,得到0xD800
。低 10 位与
0xDC00
做和,得到0xDC00
。综上所述,
U+10000
的十六进制 UTF-16BE 编码是D8 00 DC 00
,十六进制 UTF-16LE 编码是00 DC 00 D8
。
示例:将U+10FFFF
进行 UTF-16 编码。
U+10FFFF
处在U+10000 -> U+10FFFF
区间,因此采用代理对编码法。0x10FFFF
与0x10000
做差,得到0xFFFFF
。0xFFFFF
换算为二进制,得到1111 1111 1111 1111 1111
。将
1111 1111 1111 1111 1111
的高 10 位和低 10 位拆分,得到1111 1111 11
和11 1111 1111
。高 10 位与
0xD800
做和,得到0xDBFF
。低 10 位与
0xDC00
做和,得到0xDFFF
。综上所述,
U+10FFFF
的十六进制 UTF-16BE 编码是DB FF DF FF
,十六进制 UTF-16LE 编码是FF DB FF DF
。
解码规则
Unicode Number Range | UTF-16BE | UTF-16LE |
---|---|---|
U+0000 -> U+D7FF | 0000 -> D7FF | 0000 -> FFD7 |
U+D800 -> U+DFFF | 代理对编码法 | 代理对编码法 |
U+E000 -> U+FFFF | E000 -> FFFF | 00E0 -> FFFF |
代理对解码法:
- 确认是 BE 编码还是 LE 编码,如果是 LE 编码,先换算为 BE 格式。
- 以十六进制读取 2 字节,如果处于
U+D800 -> U+DFFF
区间,则是代理对编码法。 - 继续以十六进制读取 2 字节,如果处于
U+D800 -> U+DFFF
区间,则是代理对编码法。 - 如果后面的 2 字节比前面的 2 字节大,这 4 个字节属于 1 对有效的代理对。
- 如果后面的 2 字节比前面的 2 字节小,则反向读取 2 字节。
- 前面的 2 字节与
0xD800
做差,将差换算为 10 位二进制。 - 后面的 2 字节与
0xDC00
做差,将差换算为 10 位二进制。 - 将 2 对差按照从前到后的顺序排列,换算为十六进制。
- 将结果与
0x10000
求和,所得的最终结果即为 Unicode 码点。
示例:将00 65 00 6E 00 67
进行 UTF-16BE 解码。
00 65
处于U+0000 -> U+D7FF
区间,因此 UTF-16BE 编码就是 Unicode 码点。根据 Unicode 码表,
00 65
对应的字符是e
。00 6E
处于U+0000 -> U+D7FF
区间,因此 UTF-16BE 编码就是 Unicode 码点。根据 Unicode 码表,
00 6E
对应的字符是n
。00 67
处于U+0000 -> U+D7FF
区间,因此 UTF-16BE 编码就是 Unicode 码点。根据 Unicode 码表,
00 67
对应的字符是g
。综上所述,
00 65 00 6E 00 67
UTF-16BE 解码的结果就是eng
。
示例:将65 00 6E 00 67 00
进行 UTF-16LE 解码。
65 00
属于 LE 编码,换算为 BE 编码为00 65
。00 65
处于U+0000 -> U+D7FF
区间,因此 UTF-16BE 编码就是 Unicode 码点。根据 Unicode 码表,
00 65
对应的字符是e
。6E 00
属于 LE 编码,换算为 BE 编码为00 6E
。00 6E
处于U+0000 -> U+D7FF
区间,因此 UTF-16BE 编码就是 Unicode 码点。根据 Unicode 码表,
00 6E
对应的字符是n
。67 00
属于 LE 编码,换算为 BE 编码为00 67
。00 67
处于U+0000 -> U+D7FF
区间,因此 UTF-16BE 编码就是 Unicode 码点。根据 Unicode 码表,
00 67
对应的字符是g
。综上所述,
65 00 6E 00 67 00
UTF-16BE 解码的结果就是eng
。
示例:将4E 2D 65 87
进行 UTF-16BE 解码。
4E 2D
处于U+0000 -> U+D7FF
区间,因此 UTF-16BE 编码就是 Unicode 码点。根据 Unicode 码表,
4E 2D
对应的字符是中
。65 87
处于U+0000 -> U+D7FF
区间,因此 UTF-16BE 编码就是 Unicode 码点。根据 Unicode 码表,
65 87
对应的字符是文
。综上所述,
4E 2D 65 87
UTF-16BE 解码的结果就是中文
。
示例:将2D 4E 87 65
进行 UTF-16LE 解码。
2D 4E
属于 LE 编码,换算为 BE 编码为4E 2D
。4E 2D
处于U+0000 -> U+D7FF
区间,因此 UTF-16BE 编码就是 Unicode 码点。根据 Unicode 码表,
4E 2D
对应的字符是中
。87 65
属于 LE 编码,换算为 BE 编码为65 87
。65 87
处于U+0000 -> U+D7FF
区间,因此 UTF-16BE 编码就是 Unicode 码点。根据 Unicode 码表,
65 87
对应的字符是文
。综上所述,
4E 2D 65 87
UTF-16LE 解码的结果就是中文
。
示例:将D8 00 DC 00
进行 UTF-16BE 解码。
D8 00
处于U+D800 -> U+DFFF
区间,因此属于代理对编码法。继续读取下 2 个字节。
DC 00
处于U+D800 -> U+DFFF
区间,因此属于代理对编码法。DC 00
比D8 00
大,所以确认为D8 00 DC 00
为 1 对有效的代理对。D8 00
与D8 00
做差,得到00 00
。00 00
换算为 10 位二进制得到00 0000 0000
。DC 00
与DC 00
做差,得到00 00
。00 00
换算为 10 位二进制得到00 0000 0000
。将高 10 位和低 10 位合并,得到
0000 0000 0000 0000 0000
。将
0000 0000 0000 0000 0000
换算为十六进制,得到0x00000
。将
0x00000
和0x10000
求和,得到0x10000
。综上所述,
00 D8 00 DC
UTF-16BE 解码的结果就是U+10000
。
示例:将00 D8 00 DC
进行 UTF-16LE 解码。
00 D8
属于 LE 编码,换算为 BE 编码为D8 00
。D8 00
处于U+D800 -> U+DFFF
区间,因此属于代理对编码法。继续读取下 2 个字节。
00 DC
属于 LE 编码,换算为 BE 编码为DC 00
。DC 00
处于U+D800 -> U+DFFF
区间,因此属于代理对编码法。DC 00
比D8 00
大,所以确认为00 D8 00 DC
为 1 对有效的代理对。D8 00
与D8 00
做差,得到00 00
。00 00
换算为 10 位二进制得到00 0000 0000
。DC 00
与DC 00
做差,得到00 00
。00 00
换算为 10 位二进制得到00 0000 0000
。将高 10 位和低 10 位合并,得到
0000 0000 0000 0000 0000
。将
0000 0000 0000 0000 0000
换算为十六进制,得到0x00000
。将
0x00000
和0x10000
求和,得到0x10000
。综上所述,
00 D8 00 DC
UTF-16LE 解码的结果就是U+10000
。
示例:将DB FF DF FF
进行 UTF-16BE 解码。
DB FF
处于U+D800 -> U+DFFF
区间,因此属于代理对编码法。继续读取下 2 个字节。
DF FF
处于U+D800 -> U+DFFF
区间,因此属于代理对编码法。DF FF
比DB FF
大,所以确认为DB FF DF FF
为 1 对有效的代理对。DB FF
与D8 00
做差,得到03 FF
。03 FF
换算为 10 位二进制得到11 1111 1111
。DF FF
与DC 00
做差,得到03 FF
。03 FF
换算为 10 位二进制得到11 1111 1111
。将高 10 位和低 10 位合并,得到
1111 1111 1111 1111 1111
。将
1111 1111 1111 1111 1111
换算为十六进制,得到0xFFFFF
。将
0xFFFFF
和0x10000
求和,得到0x10FFFF
。综上所述,
DB FF DF FF
UTF-16BE 解码的结果就是U+10FFFF
。
示例:将FF DB FF DF
进行 UTF-16LE 解码。
FF DB
属于 LE 编码,换算为 BE 编码为DB FF
。DB FF
处于U+D800 -> U+DFFF
区间,因此属于代理对编码法。继续读取下 2 个字节。
FF DF
属于 LE 编码,换算为 BE 编码为DF FF
。DF FF
比DB FF
大,所以确认为DB FF DF FF
为 1 对有效的代理对。DB FF
与D8 00
做差,得到03 FF
。03 FF
换算为 10 位二进制得到11 1111 1111
。DF FF
与DC 00
做差,得到03 FF
。03 FF
换算为 10 位二进制得到11 1111 1111
。将高 10 位和低 10 位合并,得到
1111 1111 1111 1111 1111
。将
1111 1111 1111 1111 1111
换算为十六进制,得到0xFFFFF
。将
0xFFFFF
和0x10000
求和,得到0x10FFFF
。综上所述,
FF DB FF DF
UTF-16LE 解码的结果就是U+10FFFF
。
参考资料
本文作者: jsweibo
本文链接: https://jsweibo.github.io/2019/03/22/%E4%BB%80%E4%B9%88%E6%98%AFUTF-16/
本文对你有帮助?请支持我
- 本文链接: https://jsweibo.github.io/2019/03/22/%E4%BB%80%E4%B9%88%E6%98%AFUTF-16/
- 版权声明: 除非另有说明,否则本网站上的内容根据署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。