代理对是如何计算的?

问题描述 投票:0回答:3

如果 unicode 代码点使用 17 位或更多,则代理对如何计算?

unicode utf-8 utf-16
3个回答
9
投票

Unicode 代码点是范围从 0x000000 到 0x10FFFF 的标量值。因此它们是 21 位整数,而不是 17 位。

代理对是UTF-16形式的一种机制。这将 21 位标量值表示为一个或两个 16 位代码单元。

  • 从 0x000000 到 0x00FFFF 的标量值表示为从 0x0000 到 0xFFFF 的单个 16 位代码单元。
  • 从 0x00D800 到 0x00DFFF 的标量值不是 Unicode 中的字符,因此它们永远不会出现在 Unicode 字符串中。
  • 从 0x010000 到 0x10FFFF 的标量值表示为两个 16 位代码单元。第一个代码单元对标量值的高11位进行编码,作为范围从0xD800-0xDBFF的代码单元。将 0x01-0x10 之间的值编码为四位有点棘手。第二编码单元对标量值的低10位进行编码,作为范围从0xDC00-0xDFFF的编码单元。

Unicode 联盟的常见问题解答UTF-8、UTF-16、UTF-32 和 BOM 中通过示例代码详细解释了这一点。该常见问题解答引用了 Unicode 标准的部分,其中包含更多详细信息。


7
投票

如果您需要的是代码,以下是单个代码点分别以 UTF-16 和 UTF-8 进行编码的方式。

UTF-16 代码单元的单个代码点:

if (cp < 0x10000u)
{
   *out++ = static_cast<uint16_t>(cp);
}
else
{
   *out++ = static_cast<uint16_t>(0xd800u + (((cp - 0x10000u) >> 10) & 0x3ffu));
   *out++ = static_cast<uint16_t>(0xdc00u + ((cp - 0x10000u) & 0x3ffu));
}

UTF-8 代码单元的单个代码点:

if (cp < 0x80u)
{
   *out++ = static_cast<uint8_t>(cp);
}
else if (cp < 0x800u)
{
   *out++ = static_cast<uint8_t>((cp >> 6) & 0x1fu | 0xc0u);
   *out++ = static_cast<uint8_t>((cp & 0x3fu) | 0x80u);
}
else if (cp < 0x10000u)
{
   *out++ = static_cast<uint8_t>((cp >> 12) & 0x0fu | 0xe0u);
   *out++ = static_cast<uint8_t>(((cp >> 6) & 0x3fu) | 0x80u);
   *out++ = static_cast<uint8_t>((cp & 0x3fu) | 0x80u);
}
else
{
   *out++ = static_cast<uint8_t>((cp >> 18) & 0x07u | 0xf0u);
   *out++ = static_cast<uint8_t>(((cp >> 12) & 0x3fu) | 0x80u);
   *out++ = static_cast<uint8_t>(((cp >> 6) & 0x3fu) | 0x80u);
   *out++ = static_cast<uint8_t>((cp & 0x3fu) | 0x80u);
}

0
投票

这是一个希望对初学者更友好的阐述。

代理代码点的范围为 0xD800-0xDF00。该空间的前半部分用于代理的上半部分,后半部分用于下半部分。

因此,要对 U+10000 进行编码,请将其分成两半,并将它们塞入可用的插槽中。

D8 00 DC 00

同样,对 U+10FFFF 进行编码,可以得到

DB FF DF FF

换句话说,从 D800 到 DBFF 的值的 D800 部分被屏蔽,余数用于代码点完整值的前半部分。类似地,从 DC00 到 DFFF 的值已屏蔽掉 DC00,余数用于编码码点的低部分。

U+0001 0000 = base 0x00010000 + 0x0000
= 00 0000 0000 00 0000 0000
  mm nnnn nnnn pp qqqq qqqq

U+0010 FFFF = base 0x00010000 + 0xFFFF
= 11 1111 1111 11 1111 1111
  mm nnnn nnnn pp qqqq qqqq

1101 10mm  nnnn nnnn   D8+xx    1110 11pp  qqqq qqqq   DC+yy
----------------------------    ----------------------------
1101 1000  0000 0000   D800     1110 1100  0000 0000   DC00
1101 1011  1111 1111   DBFF     1110 1111  1111 1111   DFFF
© www.soinside.com 2019 - 2024. All rights reserved.