String.StartsWith not working with Asian languages?
我注意到这个奇怪的问题。查看这个越南语(根据谷歌翻译)字符串:
1 2 3 4 5 6 7 8 | string line ="Mìng-d??ng-ng??"; string sub ="Mìng-d??ng-ng?"; line.Length 15 sub.Length 14 line.StartsWith(sub) false |
在我看来这是个错误的结果。所以,我实现了我的自定义
1 2 3 4 5 6 7 8 9 | public bool CustomStartWith(string parent, string child) { for (int i = 0; i < child.Length; i++) { if (parent[i] != child[i]) return false; } return true; } |
正如我假设的,运行这个函数的结果
1 2 | CustomStartWith("Mìng-d??ng-ng??","Mìng-d??ng-ng?") true |
这是怎么回事?!这怎么可能?
如果确实需要将字符串视为纯字节序列的比较,请使用重载:
1 | line.StartsWith(sub, StringComparison.Ordinal); // true |
如果希望比较不区分大小写:
1 | line.StartsWith(sub, StringComparison.OrdinalIgnoreCase); // true |
下面是一个更熟悉的例子:
1 2 3 4 5 6 7 8 | 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 |
在上述示例中,
在现实语义学中,人们通常不认为
根据您的示例调整此解释:
1 2 | 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个代码单元是相同的,这就是为什么逐字符比较的结果是真的(就像
这不是错误。事实上,
所以这意味着如果你不想使用所有这些特定于区域性的设置,只想使用顺序比较来检查它,你必须告诉比较器这一点。
这是正确的方法(不要像道格拉斯那样忽视这个案例!):
1 | line.StartsWith(sub, StringComparison.Ordinal); |