Jep*_*sen 42 .net c# sorting string-comparison
在.NET中,某些字符串不是这样的:
static void CompareBug()
{
string x = "\u002D\u30A2"; // or just "-?" if charset allows
string y = "\u3042"; // or just "?" if charset allows
Console.WriteLine(x.CompareTo(y)); // positive one
Console.WriteLine(y.CompareTo(x)); // positive one
Console.WriteLine(StringComparer.InvariantCulture.Compare(x, y)); // positive one
Console.WriteLine(StringComparer.InvariantCulture.Compare(y, x)); // positive one
var ja = StringComparer.Create(new CultureInfo("ja-JP", false), false);
Console.WriteLine(ja.Compare(x, y)); // positive one
Console.WriteLine(ja.Compare(y, x)); // positive one
}
Run Code Online (Sandbox Code Playgroud)
你看,x它严格地大于y,并且y严格地大于x.
因为x.CompareTo(x)等等都给零(0),很明显这不是一个订单.毫不奇怪,当我的Sort数组或包含类似x和的字符串的列表时,我得到了不可预知的结果y.虽然我没有测试过这一点,我肯定SortedDictionary<string, WhatEver>会保持自己在有序和/或如果像琴弦定位的项目问题x,并y用于密钥.
这个bug是众所周知的吗?该框架的哪些版本受到影响(我正在尝试使用.NET 4.0)?
编辑:
以下是符号为负数的示例:
x = "\u4E00\u30A0"; // equiv: "??"
y = "\u4E00\u002D\u0041"; // equiv: "?-A"
Run Code Online (Sandbox Code Playgroud)
shu*_*bot 17
如果正确排序在您的问题中非常重要,只需使用序数字符串比较而不是文化敏感.只有这一个保证了你想要的传递和反对称比较.
在方法调用中指定StringComparison.Ordinal或StringComparison.OrdinalIgnoreCase值表示非语言比较,其中忽略自然语言的功能.使用这些StringComparison值调用的方法基于简单字节比较的字符串操作决策,而不是由culture进行参数化的大小写或等价表.在大多数情况下,这种方法最适合字符串的预期解释,同时使代码更快,更可靠.
它按预期工作:
Console.WriteLine(String.Compare(x, y, StringComparison.Ordinal)); // -12309
Console.WriteLine(String.Compare(y, x, StringComparison.Ordinal)); // 12309
Run Code Online (Sandbox Code Playgroud)
是的,它没有解释为什么文化敏感的比较会产生不一致的结果.嗯,奇怪的文化 - 奇怪的结果.
当我发现原因是 .Net 40 及以上比较器的奇怪行为(a1 < a2 且 a2 < a3,但 a1 > a3)。
\n\n我很难弄清楚发生了什么事,可以在这里找到:c# SortedList<string, TValue>.ContainsKey for successly linked key returns false。
\n\n您可能想看看我的 SO 问题的“更新 3”部分。该问题似乎于 2012 年 12 月向 Microsoft 报告,并于 2013 年 1 月底之前以“无法修复”为由关闭。此外,它还列出了可以使用的解决方法。
\n\n我创建了此建议解决方法的实现,并验证它解决了我遇到的问题。我还刚刚验证这可以解决您报告的问题。
\n\npublic static void SO_13254153_Question()\n{\n string x = "\\u002D\\u30A2"; // or just "-\xe3\x82\xa2" if charset allows\n string y = "\\u3042"; // or just "\xe3\x81\x82" if charset allows \n\n var invariantComparer = new WorkAroundStringComparer();\n var japaneseComparer = new WorkAroundStringComparer(new System.Globalization.CultureInfo("ja-JP", false));\n Console.WriteLine(x.CompareTo(y)); // positive one\n Console.WriteLine(y.CompareTo(x)); // positive one\n Console.WriteLine(invariantComparer.Compare(x, y)); // negative one\n Console.WriteLine(invariantComparer.Compare(y, x)); // positive one\n Console.WriteLine(japaneseComparer.Compare(x, y)); // negative one\n Console.WriteLine(japaneseComparer.Compare(y, x)); // positive one\n}\nRun Code Online (Sandbox Code Playgroud)\n\n剩下的问题是,这种解决方法太慢了,对于大型字符串集合来说几乎不实用。因此,我希望微软能够重新考虑解决这个问题,或者有人知道更好的解决方法。
\n| 归档时间: |
|
| 查看次数: |
2612 次 |
| 最近记录: |