关于字符类,哪个.NET平台和Windows版本支持哪个Unicode版本?

27

更新的问题 ¹

关于字符类、比较、排序、规范化和排序规则,哪些 .NET 平台支持哪个 Unicode 版本或版本?

原始问题

我有点模糊地记得 .NET 支持 Unicode 版本 3.0,并且内部的 UTF-16 编码实际上并不是真正的 UTF-16,而是使用的 UCS-2,这是不同的。例如,似乎不可能存在 U+FFFF 以上的字符,即考虑:

string s = "\u1D7D9"; // ("Mathematical double-struck digit one") 

它将字符串"ᵽ9"存储。

我基本上在寻找以下问题的明确参考答案:

  • .NET中不是真正的UTF-16,那它是什么?
  • .NET支持哪个版本的Unicode?
  • 如果最近的版本不受支持或计划在不久的将来不受支持,是否有人知道(非)商业库或我如何解决此问题的方法?

¹)随着时间的流逝,我更新了问题,因为这似乎更符合答案和更大的社区。我保留了原始问题,其中部分已在评论中回答。而且在现代32位Windows版本中使用了旧的UCS-2(没有代理),.NET始终在内部使用UTF-16(带有代理)。


1
你想用这些字符做什么?是将它们放在ASP.NET网页中吗?还是在WPF或WinForms界面中显示它们? - Joe Strommen
2
在这个上下文中,“似乎不起作用”是什么意思? - Gabe
@JoeStrommen:我们正在实施一套基于XML的数据转换工具集,我正在尝试找出是否可以说“我们支持Unicode 6.0及以下”,或者我们应该说些其他的话。此外,我正在努力找出如何绕过.NET可能存在的限制。 - Abel
@Gabe:我更新了我的问题,希望现在更清楚了。 - Abel
哦,看起来你在 C# 中使用了错误的转义机制——这与 .NET 无关。你的字符串被解释为 "\u1D7D" + "9"。你只需要使用 "\U0001D7D9"。 - Gabe
@Gabe:确实,我不知道\U(我猜以前从没用过),然后错误地得出结论认为不支持更高的平面。 - Abel
4个回答

19

在内部,.NET使用UTF-16编码。在某些情况下,例如ASP.NET写入响应时,默认情况下它使用UTF-8编码。两种编码都可以处理高位平面。

人们有时将.NET称为UCS2的原因是(我认为是这个原因,因为我没有看到其他原因),Char严格为16位,单个Char无法用于表示上层平面。但是,Char具有静态方法重载(例如Char.IsLetter),可以在字符串中操作高位UTF-16字符。字符串以真正的UTF-16格式存储。

您可以使用大写的\U直接访问高Unicode代码点,例如"\U0001D7D9",但同样只能在字符串中使用,而不能使用于字符。

至于Unicode版本,来自MSDN文档

"在.NET Framework 4中,排序、大小写转换、规范化和Unicode字符信息与Windows 7同步,并符合Unicode 5.1标准。"

更新1:值得注意的是,这并不意味着在Windows 7或.NET 4.0中支持整个Unicode 5.1 -

Windows 8目标是Unicode 6.0 - 我猜想.NET Framework 4.5可能会与之同步,但没有找到证实它的来源。再一次强调,这并不意味着整个标准都被实现了。

更新2:这篇Roslyn的说明确认底层平台定义了编译器的Unicode支持,在代码链接中解释了C# 6.0支持Unicode 6.0及以上版本(因此对C#标识符造成了破坏性变更)。

更新3: 自从.NET 4.5版本,引入了一个 新类 SortVersion 通过调用静态属性 SortVersion.FullVersion 来获取支持的Unicode版本。在同一页上,微软解释说 .NET 4.0 在所有平台上都支持Unicode 5.0,而.NET 4.5在 Windows 7上支持 Unicode 5.0,在Windows 8上支持Unicode 6.0。这与官方的“新功能”声明略有不同,后者分别讨论了版本5.x和6.0。从我自己(Abel)的经验来看,在大多数情况下,似乎至少在字符类中支持.NET 4.0 的 Unicode 5.1,但我没有测试排序、规范化和排序。这似乎符合上面引用的MSDN所说的内容。

1
关于 char 的好观察。我确实注意到 char uni = "\U0002B740".ToCharArray()[0]; 显示为 "55405",这只是 UTF-16 代理对的一半。根据您提供的参考,尝试在 \u0526 上使用 Char.IsLetter(不正确)会显示 false,因为它仅在 Unicode 6 中引入。 - Abel
1
接受此回答,因为您提供了我正在寻找但无法在明显位置找到的参考资料,然而其他答案也有其自身的价值。 - Abel
1
这可能是获取单个字符信息的一个有用起点:MSDN链接。由于char不能包含超过一半的内容,因此StringInfo方法返回一个字符串,其中包含完整的UTF-16对(如果字符是一对 - 否则它只返回单个字符 - 作为字符串或字符+组合重音符号的组合)。 - JimmiTh
现在这就有意义了。C# 语言规范将 char 视为一个无符号的 16 位 整数类型。因此,似乎它被设计为具有固定的宽度,这也解释了为什么它不支持 UTF-16 代理项。 - Nicholas Miller
自从.NET 4.5版本以来,引入了一个新的类SortVersion,通过调用静态属性SortVersion.FullVersion可以获取支持的Unicode版本。请注意,SortVersion.FullVersion不是静态的。 - canton7

5
支持该字符。需要注意的是,对于超过2个字节的Unicode字符,您必须使用大写“\ U”进行声明,像这样: string text = "\U0001D7D9" 如果在文本块中创建带有该字符的WPF应用程序,则应完美呈现双一字符。

1
还有一件事:阅读 http://msdn.microsoft.com/en-us/library/aa664669(v=vs.71).aspx 了解字符串中如何表示多于2个字节的字符。 - Joe Strommen

4

MSDN在此简要介绍了它:http://msdn.microsoft.com/en-us/library/9b1s4yhz(v=vs.90).aspx

我尝试过这个:

    static void Main(string[] args) {
        string someText = char.ConvertFromUtf32(0x1D7D9);
        using (var stream = new MemoryStream()) {
            using (var writer = new StreamWriter(stream, Encoding.UTF32)) {
                writer.Write(someText);
                writer.Flush();
            }
            var bytes = stream.ToArray();
            foreach (var oneByte in bytes) {
                Console.WriteLine(oneByte.ToString("x"));
            }
        }
    }

我得到了一个字节数组的转储,其中包含正确的BOM和正确表示\u1D7D9码点的编码方式,这些编码方式为:

  • UTF8
  • UTF32
  • Unicode (UTF-16)

因此,我的猜测是支持更高的平面,并且UTF-16确实是UTF-16 (而不是UCS-2)


感谢您展示了一种简单的方法。看起来确实是UTF-16而不是UCS-2(不再是?)。该字符及其所有编码在此处:http://www.fileformat.info/info/unicode/char/1d7d9/index.htm - Abel
顺便说一下,我看了那个参考资料,但没有找到有关Unicode支持的具体信息。 - Abel

0

.NET Framework 4.6、4.5、4、3.5和3.0 - Unicode标准,版本5.0 .NET Framework 2.0和1.1 - Unicode标准,版本3.1

完整的答案可以在此处的备注部分找到。


看看我对原回答所做的修改,它并不像那个MSDN页面所暗示的那样。事实上,该页面只讨论Unicode字符类别,这与字符编码或支持的字符范围不同,但即使在框架版本和底层操作系统之间也存在差异。有关更多信息,请参见SortVersion的MSDN文章(但请注意,即使该页面也不完整)。 - Abel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接