使用Encoding.Unicode映射到奇数字节的字符

时间:2018-08-23 01:12:52

标签: c# .net unicode encoding

我知道在某些情况下,使用Encoding.Unicode.GetBytes()时某些字符会占用更多空间。例如:

var value = Encoding.Unicode.GetBytes("");,其中value.Length为4。

这不同于:

var value = Encoding.Unicode.GetBytes("a");,其中value.Length为2。

但是,我真的很好奇。是否有可能提出一组字符,这些字符可能导致Encoding.Unicode.GetBytes()返回奇数个字节,也许使用组合字符或其他方式?如果是这样,有人可以告诉我一个这样的例子吗?如果没有,那为什么呢?

2 个答案:

答案 0 :(得分:1)

根据UTF-16,这些范围内的字符具有以下字节大小:

U + 0000至U + D7FF:2个字节。

U + E000到U + FFFF:2个字节。

U + D800到U + DFFF:保留以区分代理对(请参见下文),并且不应进行编码,但是,尽管官方Unicode标准说没有包括UTF-16在内的UTF形式都可以对这些代码点进行编码,仍然可以在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

答案 1 :(得分:0)

我认为您可能在代码点和字节数或如何组合字符以创建字符串方面有些误导。有2**16个代码点,可以想像一下枚举每个代码点以获取值并返回字节(如果需要确认)。

Unicode具有用于描述字符的“平面”(出于这个问题的考虑,假定使用UTF-16,因为这些范围随UTF-8和UTF-32的变化而变化)。字节的特定组合会创建“对”,尽管它们仍然代表一个字符,但实际上占用了4个字节来描述。

在UTF-16中,这些是码点值大于0x00FFFF的字符,它们均为4个字节,而等于或小于2的任何字符都将使用2个字节。正如我已经说过的,这仅适用于UTF-16。

因此,尽管字节数可能会略有变化(尽管可以预测),但值始终是偶数,它们将是2或4。