什么是UTF-16


本文作者: jsweibo

本文链接: https://jsweibo.github.io/2019/03/22/%E4%BB%80%E4%B9%88%E6%98%AFUTF-16/

摘要

本文主要讲述了:

  1. 什么是 UTF-16
  2. 编码规则
  3. 解码规则

正文

什么是 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 代理对编码法 代理对编码法

代理对编码法:

  1. 将十六进制的 Unicode 码点与0x10000做差。
  2. 将差换算为 20 位的二进制。
  3. 将 20 位二进制拆分为高 10 位和低 10 位。
  4. 将高 10 位与0xD800做和。
  5. 将低 10 位与0xDC00做和。
  6. 两个和按照 BE 排列,就是 UTF-16 的十六进制 BE 编码。
  7. 两个和按照 LE 排列,就是 UTF-16 的十六进制 LE 编码。

示例:将eng进行 UTF-16 编码。

  1. e的 Unicode 码点是U+0065

  2. U+0065处在U+0000 -> U+D7FF区间,因此 UTF-16BE 编码就是 Unicode 码点。

  3. e的十六进制 UTF-16BE 编码是00 65,十六进制 UTF-16LE 编码是65 00

  4. n的 Unicode 码点是U+006E

  5. U+006E处在U+0000 -> U+D7FF区间,因此 UTF-16BE 编码就是 Unicode 码点。

  6. n的十六进制 UTF-16BE 编码是00 6E,十六进制 UTF-16LE 编码是6E 00

  7. g的 Unicode 码点是U+0067

  8. U+0067处在U+0000 -> U+D7FF区间,因此 UTF-16BE 编码就是 Unicode 码点。

  9. g的十六进制 UTF-16BE 编码是00 67,十六进制 UTF-16LE 编码是67 00

  10. 综上所述,eng的十六进制 UTF-16BE 编码是00 65 00 6E 00 67,十六进制 UTF-16LE 编码是65 00 6E 00 67 00

示例:将中文进行 UTF-16 编码。

  1. 的 Unicode 码点是U+4E2D

  2. U+4E2D处在U+0000 -> U+D7FF区间,因此 UTF-16BE 编码就是 Unicode 码点。

  3. 的十六进制 UTF-16BE 编码是4E 2D,十六进制 UTF-16LE 编码是2D 4E

  4. 的 Unicode 码点是U+6587

  5. U+6587处在U+0000 -> U+D7FF区间,因此 UTF-16BE 编码就是 Unicode 码点。

  6. 的十六进制 UTF-16BE 编码是65 87,十六进制 UTF-16LE 编码是87 65

  7. 综上所述,中文的十六进制 UTF-16BE 编码是4E 2D 65 87,十六进制 UTF-16LE 编码是2D 4E 87 65

示例:将U+10000进行 UTF-16 编码。

  1. U+10000处在U+10000 -> U+10FFFF区间,因此采用代理对编码法。

  2. 0x100000x10000做差,得到0x00000

  3. 0x00000换算为二进制,得到0000 0000 0000 0000 0000‬

  4. 0000 0000 0000 0000 0000的高 10 位和低 10 位拆分,得到0000 0000 0000 0000 0000

  5. 高 10 位与0xD800做和,得到0x‭D800

  6. 低 10 位与0xDC00做和,得到0x‭DC00‬

  7. 综上所述,U+10000的十六进制 UTF-16BE 编码是D8 00 DC 00,十六进制 UTF-16LE 编码是00 DC 00 D8

示例:将U+10FFFF进行 UTF-16 编码。

  1. U+10FFFF处在U+10000 -> U+10FFFF区间,因此采用代理对编码法。

  2. 0x10FFFF0x10000做差,得到‭0xFFFFF

  3. 0xFFFFF换算为二进制,得到1111 ‭1111 1111 1111 1111‬

  4. 1111 1111 1111 1111 1111的高 10 位和低 10 位拆分,得到1111 1111 1111 1111 1111

  5. 高 10 位与0xD800做和,得到‭0xDBFF‬

  6. 低 10 位与0xDC00做和,得到‭0xDFFF‬

  7. 综上所述,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

代理对解码法:

  1. 确认是 BE 编码还是 LE 编码,如果是 LE 编码,先换算为 BE 格式。
  2. 以十六进制读取 2 字节,如果处于U+D800 -> U+DFFF区间,则是代理对编码法。
  3. 继续以十六进制读取 2 字节,如果处于U+D800 -> U+DFFF区间,则是代理对编码法。
  4. 如果后面的 2 字节比前面的 2 字节大,这 4 个字节属于 1 对有效的代理对。
  5. 如果后面的 2 字节比前面的 2 字节小,则反向读取 2 字节。
  6. 前面的 2 字节与0xD800做差,将差换算为 10 位二进制。
  7. 后面的 2 字节与0xDC00做差,将差换算为 10 位二进制。
  8. 将 2 对差按照从前到后的顺序排列,换算为十六进制。
  9. 将结果与0x10000求和,所得的最终结果即为 Unicode 码点。

示例:将00 65 00 6E 00 67进行 UTF-16BE 解码。

  1. 00 65处于U+0000 -> U+D7FF区间,因此 UTF-16BE 编码就是 Unicode 码点。

  2. 根据 Unicode 码表,00 65对应的字符是e

  3. 00 6E处于U+0000 -> U+D7FF区间,因此 UTF-16BE 编码就是 Unicode 码点。

  4. 根据 Unicode 码表,00 6E对应的字符是n

  5. 00 67处于U+0000 -> U+D7FF区间,因此 UTF-16BE 编码就是 Unicode 码点。

  6. 根据 Unicode 码表,00 67对应的字符是g

  7. 综上所述,00 65 00 6E 00 67UTF-16BE 解码的结果就是eng

示例:将65 00 6E 00 67 00进行 UTF-16LE 解码。

  1. 65 00属于 LE 编码,换算为 BE 编码为00 65

  2. 00 65处于U+0000 -> U+D7FF区间,因此 UTF-16BE 编码就是 Unicode 码点。

  3. 根据 Unicode 码表,00 65对应的字符是e

  4. 6E 00属于 LE 编码,换算为 BE 编码为00 6E

  5. 00 6E处于U+0000 -> U+D7FF区间,因此 UTF-16BE 编码就是 Unicode 码点。

  6. 根据 Unicode 码表,00 6E对应的字符是n

  7. 67 00属于 LE 编码,换算为 BE 编码为00 67

  8. 00 67处于U+0000 -> U+D7FF区间,因此 UTF-16BE 编码就是 Unicode 码点。

  9. 根据 Unicode 码表,00 67对应的字符是g

  10. 综上所述,65 00 6E 00 67 00UTF-16BE 解码的结果就是eng

示例:将4E 2D 65 87进行 UTF-16BE 解码。

  1. 4E 2D处于U+0000 -> U+D7FF区间,因此 UTF-16BE 编码就是 Unicode 码点。

  2. 根据 Unicode 码表,4E 2D对应的字符是

  3. 65 87处于U+0000 -> U+D7FF区间,因此 UTF-16BE 编码就是 Unicode 码点。

  4. 根据 Unicode 码表,65 87对应的字符是

  5. 综上所述,4E 2D 65 87UTF-16BE 解码的结果就是中文

示例:将2D 4E 87 65进行 UTF-16LE 解码。

  1. 2D 4E属于 LE 编码,换算为 BE 编码为4E 2D

  2. 4E 2D处于U+0000 -> U+D7FF区间,因此 UTF-16BE 编码就是 Unicode 码点。

  3. 根据 Unicode 码表,4E 2D对应的字符是

  4. 87 65属于 LE 编码,换算为 BE 编码为65 87

  5. 65 87处于U+0000 -> U+D7FF区间,因此 UTF-16BE 编码就是 Unicode 码点。

  6. 根据 Unicode 码表,65 87对应的字符是

  7. 综上所述,4E 2D 65 87UTF-16LE 解码的结果就是中文

示例:将D8 00 DC 00进行 UTF-16BE 解码。

  1. D8 00处于U+D800 -> U+DFFF区间,因此属于代理对编码法。

  2. 继续读取下 2 个字节。

  3. DC 00处于U+D800 -> U+DFFF区间,因此属于代理对编码法。

  4. DC 00D8 00大,所以确认为D8 00 DC 00为 1 对有效的代理对。

  5. D8 00D8 00做差,得到00 00

  6. 00 00换算为 10 位二进制得到00 0000 0000

  7. DC 00DC 00做差,得到00 00

  8. 00 00换算为 10 位二进制得到00 0000 0000

  9. 将高 10 位和低 10 位合并,得到0000 0000 0000 0000 0000

  10. 0000 0000 0000 0000 0000换算为十六进制,得到0x00000

  11. 0x000000x10000求和,得到0x10000

  12. 综上所述,00 D8 00 DCUTF-16BE 解码的结果就是U+10000

示例:将00 D8 00 DC进行 UTF-16LE 解码。

  1. 00 D8属于 LE 编码,换算为 BE 编码为D8 00

  2. D8 00处于U+D800 -> U+DFFF区间,因此属于代理对编码法。

  3. 继续读取下 2 个字节。

  4. 00 DC属于 LE 编码,换算为 BE 编码为DC 00

  5. DC 00处于U+D800 -> U+DFFF区间,因此属于代理对编码法。

  6. DC 00D8 00大,所以确认为00 D8 00 DC为 1 对有效的代理对。

  7. D8 00D8 00做差,得到00 00

  8. 00 00换算为 10 位二进制得到00 0000 0000

  9. DC 00DC 00做差,得到00 00

  10. 00 00换算为 10 位二进制得到00 0000 0000

  11. 将高 10 位和低 10 位合并,得到0000 0000 0000 0000 0000

  12. 0000 0000 0000 0000 0000换算为十六进制,得到0x00000

  13. 0x000000x10000求和,得到0x10000

  14. 综上所述,00 D8 00 DCUTF-16LE 解码的结果就是U+10000

示例:将DB FF DF FF进行 UTF-16BE 解码。

  1. DB FF处于U+D800 -> U+DFFF区间,因此属于代理对编码法。

  2. 继续读取下 2 个字节。

  3. DF FF处于U+D800 -> U+DFFF区间,因此属于代理对编码法。

  4. DF FFDB FF大,所以确认为DB FF DF FF为 1 对有效的代理对。

  5. DB FFD8 00做差,得到03 FF

  6. 03 FF换算为 10 位二进制得到11 1111 1111

  7. DF FFDC 00做差,得到03 FF

  8. 03 FF换算为 10 位二进制得到11 1111 1111

  9. 将高 10 位和低 10 位合并,得到1111 1111 1111 1111 1111

  10. 1111 1111 1111 1111 1111换算为十六进制,得到0xFFFFF

  11. 0xFFFFF0x10000求和,得到0x10FFFF

  12. 综上所述,DB FF DF FFUTF-16BE 解码的结果就是U+10FFFF

示例:将FF DB FF DF进行 UTF-16LE 解码。

  1. FF DB属于 LE 编码,换算为 BE 编码为DB FF

  2. DB FF处于U+D800 -> U+DFFF区间,因此属于代理对编码法。

  3. 继续读取下 2 个字节。

  4. FF DF属于 LE 编码,换算为 BE 编码为DF FF

  5. DF FFDB FF大,所以确认为DB FF DF FF为 1 对有效的代理对。

  6. DB FFD8 00做差,得到03 FF

  7. 03 FF换算为 10 位二进制得到11 1111 1111

  8. DF FFDC 00做差,得到03 FF

  9. 03 FF换算为 10 位二进制得到11 1111 1111

  10. 将高 10 位和低 10 位合并,得到1111 1111 1111 1111 1111

  11. 1111 1111 1111 1111 1111换算为十六进制,得到0xFFFFF

  12. 0xFFFFF0x10000求和,得到0x10FFFF

  13. 综上所述,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/


本文对你有帮助?请支持我


支付宝
微信