我知道在某些情况下,某些字符在使用Encoding.Unicode.GetBytes()
时会占用更多空间。例如:
var value = Encoding.Unicode.GetBytes("🌀");
,value.Length
为 4。
这与以下不同:
var value = Encoding.Unicode.GetBytes("a");
,value.Length
为 2。
但是,我真的很好奇一些事情。是否有可能想出一组字符,导致Encoding.Unicode.GetBytes()
返回奇数个字节,也许使用组合字符或其他方式?如果是这样,有人可以给我看一个这样的例子吗?如果不是,为什么会这样?
根据 UTF-16,这些范围内的字符具有以下字节大小:
U+0000 到 U+D7FF:2 个字节。
U+E000 到 U+FFFF:2 个字节。
U+D800 到 U+DFFF:保留用于区分代理项对(见下文(,不应编码,但是,尽管官方 Unicode 标准规定没有 UTF 形式(包括 UTF-16(可以编码这些代码点,但它仍然适用于 C#:var value = Encoding.Unicode.GetBytes("uD800");
另请注意,使用var str = Encoding.Unicode.GetString(value);
将这些值转换回来不会给您相同的结果!
U+10000 到 U+10FFFF:4 字节字符,有两个 2 字节代理项对,利用上述保留范围。特别说明:虽然是一个字符,但它🌀实际上在 C# 字符串中存储为两个字符。以下情况是真的:Debug.Assert("🌀".Length == 2);
小心!
U+110000 及以上:不应编码,似乎也不应在 C# 中编码。例如,这不起作用:var str = "U00110000";
如果我们假设任何给定的字符分别占用 2 或 4 个字节(由于编码器的行为方式,我目前仍然不确定(,那么通过简单的数学证明,两个偶数除以 2 仍然是偶数。偶数是 2 的倍数,写为:2m + 2n
上面的公式总是能被 2 整除,因为(2m + 2n) / 2
=m + n
。
我认为您可能会在代码点和字节数或如何组合字符以创建字符串方面略有误导。有2**16
代码点,您可以枚举每个代码点以获取值并返回字节(如果要确认(。
Unicode 有"平面"来描述字符(为了这个问题,假设 UTF-16,因为这些范围随着 UTF-8 和 UTF-32 的变化而变化(。字节的特定组合创建"对",虽然它们仍然代表一个字符,但实际上占用 4 个字节来描述。
在 UTF-16 中,这些是代码点值高于0x00FFFF
的字符,它们都是 4 个字节,而任何等于或更小的字符都将使用 2 个字节。正如我已经说过的,这仅适用于 UTF-16。
因此,虽然字节数可能略有变化(尽管可以预见(,但值将始终为偶数,它们要么是 2 要么是 4。