为啥用于 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 方法有两个重载?的主要内容,如果未能解决你的问题,请参考以下文章
为啥在使用 unicode 时我不能在 :before :after 内容之后使用空格