当前位置:  开发笔记 > 编程语言 > 正文

String.Starts不使用亚洲语言?

如何解决《String.Starts不使用亚洲语言?》经验,为你挑选了2个好方法。

我注意到这个奇怪的问题.看看这个越南语(根据谷歌翻译)字符串:

string line = "Mìng-d??ng-ng??";
string sub = "Mìng-d??ng-ng?";
line.Length
15
sub.Length
14
line.StartsWith(sub)
false

在我看来,这似乎是一个错误的结果.所以,我实现了我的自定义StartWith函数,它比较字符串char-by-char.

public bool CustomStartWith(string parent, string child)
{
    for (int i = 0; i < child.Length; i++)
    {
        if (parent[i] != child[i])
            return false;
    }
    return true;
}

而我猜测,运行此功能的结果

CustomStartWith("Mìng-d??ng-ng??", "Mìng-d??ng-ng?")
true

这里发生了什么?!这怎么可能?



1> Douglas..:

返回的结果StartsWith是正确的.默认情况下,大多数字符串比较方法使用当前区域性而不是纯字节序列执行区分文化的比较.尽管您line的字节序列与之相同sub,但它所代表的子字符串在大多数(或所有)文化中并不相同.

如果您真的想要将字符串视为普通字节序列的比较,请使用重载:

line.StartsWith(sub, StringComparison.Ordinal);                       // true

如果您希望比较不区分大小写:

line.StartsWith(sub, StringComparison.OrdinalIgnoreCase);             // true

这是一个更熟悉的例子:

var line1 = "café";   // 63 61 66 E9     – precomposed character 'é' (U+00E9)
var line2 = "cafe?";   // 63 61 66 65 301 – base letter e (U+0065) and
                      //                   combining acute accent (U+0301)
var sub   = "cafe";   // 63 61 66 65 
Console.WriteLine(line1.StartsWith(sub));                             // false
Console.WriteLine(line2.StartsWith(sub));                             // false
Console.WriteLine(line1.StartsWith(sub, StringComparison.Ordinal));   // false
Console.WriteLine(line2.StartsWith(sub, StringComparison.Ordinal));   // true

在上面的例子中,line2以相同的字节序列开始sub,然后是要应用于final的组合急性重音(U + 0301)e.line1使用预组合字符为é(U + 00E9),所以它的字节序列不匹配的sub.

在现实世界的语义中,人们通常不会认为cafe是子串café; 的ee?被视为不同的字符.这e?恰好表示为一对字符开头,e是编码方案(Unicode)的内部实现细节,不应影响结果.这是由上面的例子证明了对比cafécafe?; 除非特意打算进行序数(逐字节)比较,否则不会期望得到不同的结果.

根据您的示例调整此解释:

string line = "Mìng-d??ng-ng??";   // 4D EC 6E 67 2D 64 115 324 6E 67 2D 6E 67 1E73 304
string sub  = "Mìng-d??ng-ng?";   // 4D EC 6E 67 2D 64 115 324 6E 67 2D 6E 67 1E73

每个.NET字符代表一个UTF-16代码单元,其值显示在上面的注释中.前14个代码单元是相同的,这就是为什么你的char-by-char比较评估为true(就像StringComparison.Ordinal).但是,第15个代码单元line是组合macron,◌̄(U + 0304),它与前面的?(U + 1E73)组合给出??.


但是StartsWith的默认比较器是什么?另外,为什么你使用IgnoreCase而不仅仅是Ordinal?作者使用序数比较而不忽视案例.
@VadimMartynov:我已经更新了使用`Ordinal`的例子.扩大解释.

2> Patrick Hofm..:

这不是一个错误.该String.StartsWith其实不仅仅是你的两个字符串的字符一个字符检查聪明得多.它考虑了您当前的文化(语言设置等),并考虑到收缩和特殊字符.(它不关心你最终需要两个字符??.它将它比作一个).

因此,这意味着如果您不想采用所有这些特定于文化的设置,并且只想使用序数比较来检查它,则必须告诉比较器.

这是正确的方法(不要忽视案例,就像道格拉斯那样!):

line.StartsWith(sub, StringComparison.Ordinal);


@Thilo你会说英语还是其他欧洲语言?在这些语言中,通常将字母和变音符号视为单位,但有一些例外(并且大多数例外考虑的是组合字母,而不是将它们分开).我们通常会说'naïve`和'naï̈ve`都有5个字母,`façade`和`façade`都有6个.因此.NET认为前两个是'StartsWith`,而后两个,但是给出了`因此长度为5,6,6和7.
推荐阅读
刘美娥94662
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有