给定 UTF-16 大小的最大 UTF-8 字符串大小

Mik*_*ski 5 .net c# utf-8 utf-16 character-encoding

确定对给定数量的 UTF-16 代码单元进行编码所需的最大 UTF-8 字节数(即String.LengthC# / .NET 中的值)的公式是什么?

我看到三种可能性:

  1. # of UTF-16 code units x 2

  2. # of UTF-16 code units x 3

  3. # of UTF-16 code units x 4

UTF-16 代码点由 1 个或 2 个代码单元表示,因此我们只需要考虑字符串填充其中一个或另一个的最坏情况。如果 UTF-16 字符串完全由 2 个代码单元代码点组成,那么我们知道 UTF-8 表示的大小最多相同,因为代码点在两种表示中最多占用 4 个字节,因此最坏的情况就是上面的选项(1)。

因此,需要考虑的一个有趣的情况(我不知道答案)是单个代码单元 UTF-16 代码点在 UTF-8 表示中可能需要的最大字节数。

如果所有单个代码单元 UTF-16 代码点都可以用 3 个 UTF-8 字节表示(我的直觉告诉我这是最有意义的),那么选项 (2) 将是最坏的情况。如果有任何需要 4 个字节,则选项 (3) 将是答案。

有人知道哪个是正确的吗?我真的希望(1)或(2)因为(3)会让事情变得更加困难:/

更新

据我所知,UTF-16 以单个代码单元对 BMP 中的所有字符进行编码,而所有其他平面以 2 个代码单元进行编码。

看来UTF-8可以在3个字节内编码整个BMP,并使用4个字节来编码其他平面。

因此,在我看来,上面的选项(2)是正确的答案,这应该有效:

string str = "Some string";
int maxUtf8EncodedSize = str.Length * 3;
Run Code Online (Sandbox Code Playgroud)

看起来是这样检查出来的吗?

Jas*_*rue 2

正确形成的 UTF-8 每个 Unicode 代码点最多可以有 4 个字节。

UTF-16 编码字符每个 Unicode 代码点最多可以有 2 个 16 位序列。

基本多语言平面之外的字符(包括表情符号和添加到最新版本 Unicode 中的语言)最多用 21 位表示,在 UTF-8 格式中会产生 4 个字节序列,结果也占用 4 个字节。 UTF-16 格式的字节。

然而,有些环境的行为会很奇怪。由于基本多语言平面之外的 UTF-16 字符最多需要 2 个 16 位序列(它们是可检测的,因为它们始终是 U+D800 到 U+DFFF 范围内的 16 位序列),因此一些错误的 UTF-8 实现,通常称为 CESU-8,它将这些 UTF-8 序列转换为两个 3 字节的 UTF-8 序列,每个 UTF-32 代码点总共有 6 个字节。(我相信一些早期的 Oracle DB 实现做到了这一点,而且我确信它们不是唯一的)。

还有一个小问题,即某些字形被归类为组合字符,并且在确定屏幕上显示的内容时使用多个 UTF-16(或 UTF-32)序列,但我认为这并不适用在你的情况下。

根据您的编辑,您似乎正在尝试估计 .Net 编码转换的最大长度。字符串长度测量字符总数,即 UTF-16 代码点的计数。因此,作为最坏情况的估计,我相信您可以安全地估计 count(Char) * 3,因为非 BMP 字符将是 count(Char) * 2,产生 4 个字节作为 UTF-8。

如果你想获得所表示的 UTF-32 代码点的总数,你应该能够执行类似的操作

var maximumUtf8Bytes = System.Globalization.StringInfo(myString).LengthInTextElements * 4;
Run Code Online (Sandbox Code Playgroud)

(我的 C# 有点生疏,因为过去几年我没有太多使用 .Net 环境,但我认为这可以解决问题)。

  • @Nyerguds 在早期的 Unicode 时代(Unicode 2 或 3)我认为如果 Unicode 超过了 21 位可分配的代码点,早期的规范实现理论上允许 utf-8 扩展到 6 个字节,但后来正式限制为 4 个字节,大概是因为 Unicode 标准确定为 21 位。另请参阅/sf/ask/667328091/ (2认同)