为啥用于 Unicode 属性测试的 C# System.Char 方法有两个重载?

Posted

技术标签:

【中文标题】为啥用于 Unicode 属性测试的 C# System.Char 方法有两个重载?【英文标题】:Why do C# System.Char methods for Unicode property tests have two overloads?为什么用于 Unicode 属性测试的 C# System.Char 方法有两个重载? 【发布时间】:2016-10-09 05:10:40 【问题描述】:

在methods of System.Char 中,我们看到了两种检查字符是否为符号的方法:

public static bool IsSymbol(string s, int index)
public static bool IsSymbol(char c)

对于其他属性测试也是如此:IsLower、IsLetter 等。

为什么会有这种重复?有什么理由更喜欢Char.IsSymbol(s, idx) 而不是Char.IsSymbol(s[idx])

【问题讨论】:

更好地处理 utf16 代理对可能是采用我想象的字符串的一个可能原因。 @RaphaelMiedl Yup, that's it。它使用 GetUnicodeCategory,它使用 InternalGetUnicodeCategory,它使用 InternalGetCategoryValue,它执行 UTF16 到 UTF32 的转换,这可能导致代理对的解码。 @RaymondChen:如果你能回答这个问题,我认为会很好。 看起来 Raphael 是正确的:dotnetfiddle.net/JFMrey。文档应该描述这种行为。一个字符既可以归类为高代理,也可以归类为字母,这也很有趣。 Unicode 需要一个或两个字符来编码一个代码点,当您编写 C# 代码时这是一个非常正确的参数。它不是唯一的,一些语言设计人员在 C# 出现之前很久就发现 utf16 存在问题,并决定弱支持 System.Char,要求程序员使用字符串重载。就像每个 C# 程序员都喜欢不喜欢的语言一样,它不应该被命名:) 【参考方案1】:

从表面上看,两个重载在功能上似乎是相同的,但深入到对 InternalGetUnicodeCategory 的调用会发现它们导致调用 CharUnicodeInfo.GetUnicodeCateogry 的不同重载。

string,int 重载最终会通过 InternalConvertToUtf32 进行 UTF32 转换,然后再调用同一个 char InternalGetUnicodeCategory 函数。这说明了解码 UTF16 编码字符中的代理对的可能性。

   internal static UnicodeCategory InternalGetUnicodeCategory(String value, int index) 
        Contract.Assert(value != null, "value can not be null");
        Contract.Assert(index < value.Length, "index < value.Length");

        return (InternalGetUnicodeCategory(InternalConvertToUtf32(value, index)));
    

Check out the Conversion implementation here if you want.

您可能会问为什么这很重要?那么答案是.Net 支持文本元素。微软声明:

MSDN Documentation on Unicode Support for Surrogate Pairs

文本元素是显示为单个字符的文本单元,称为字形。文本元素可以是基本字符、代理对或组合字符序列。

虽然我不相信IsSymbol 函数及其亲属可以解码字形或组合字符序列,但标注文本元素的原因是它们可以定义为代理对,因此需要通过IsSymbol(), IsLetter() 等的string,int 重载进行解码...

这意味着通过char 重载传递代理对将返回错误结果,因为字符串中的字符可能 是代理对。您不能假设 16 位编码代表单个字符,并且在所述索引处传递字符串的字符会做出这样的假设。

因为代理对可以在 .Net 中的字符串中表示,所以如果您正在处理一个可能包含其中之一的字符串,那么IsSymbol(string s, int index) 重载会更合适为了涵盖其中一对存在的情况。

结果不同的一个具体例子是

string s = char.ConvertFromUtf32(128204); // "?"

Debug.Assert(char.IsSymbol(s[0]) == char.IsSymbol(s, 0)); // Fails

【讨论】:

更新了一个更简洁和尖锐的答案......希望:) 您确定 char.IsSymbol() 等对组合字符序列进行操作吗?这更令人惊讶。根据前面的讨论,我希望它们只对代码点进行操作(即只解码代理对)。 我不确定在组合序列的情况下,但是文本元素被定义为代理对组合字符序列,所以我真的只是在回答他们过载的潜在原因。看看它们是否也对序列进行操作会很有趣。 @ridiculous_fish Unicode 字符属性仅在每个代码点的基础上定义,因此处理整个组合字符序列/字素簇没有多大意义。此外,快速查看链接转换函数似乎可以确认它仅通过 utf32 转换使用代码点。引用似乎更多地是关于 C# 中的一般 unicode 支持,而不是特定于 IsSymbol() 函数。 我同意。 @EvanL,如果您更新您的答案以反映这一点(IsSymbol() 和朋友解码代理)并删除对字形和文本元素的讨论,我会接受您的答案。

以上是关于为啥用于 Unicode 属性测试的 C# System.Char 方法有两个重载?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 C# 禁止泛型属性类型?

为啥在使用 unicode 时我不能在 :before :after 内容之后使用空格

为啥 C++ 标准没有像 C# 一样添加“属性”?

为啥获取私有属性一无所获? (c#) [关闭]

何时以及为啥需要supportedRuntime 元素和sku 属性?

为啥 C++ CLI 索引属性在 C# 中不起作用?