.NET Framework中字符串比较中的错误

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

如果正确排序在您的问题中非常重要,只需使用序数字符串比较而不是文化敏感.只有这一个保证了你想要的传递和反对称比较.

MSDN说的是什么:

在方法调用中指定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)

是的,它没有解释为什么文化敏感的比较会产生不一致的结果.嗯,奇怪的文化 - 奇怪的结果.

  • 在某些情况下,序数比较可以是相关选项,但它不会改变它不是默认值的事实,并且它确实使其他比较类型的实现中的错误合法化.奇怪的文化?我同意**`InvariantCulture`**是一种奇怪的文化,但这个问题发生在所有.NET文化中.如果你指的是日本文化,我认为日本文化中没有任何东西可以说某些东西可以同时大于和小于其他东西? (3认同)
  • 当然,你是对的.我在开玩笑.您真的可以尝试将此错误提交给[Microsoft](http://connect.microsoft.com/VisualStudio). (3认同)

Ale*_*lex 1

当我发现原因是 .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\n
public 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}\n
Run Code Online (Sandbox Code Playgroud)\n\n

剩下的问题是,这种解决方法太慢了,对于大型字符串集合来说几乎不实用。因此,我希望微软能够重新考虑解决这个问题,或者有人知道更好的解决方法。

\n