本文作者: 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 67UTF-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 00UTF-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 87UTF-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 87UTF-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 DCUTF-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 DCUTF-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 FFUTF-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 DFUTF-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) 进行许可。