为什么(“abc”+ char.MaxValue).CompareTo(“abc”)== 0?

时间:2012-11-20 11:01:28

标签: c#

我有一个排序的字符串数组。 给定一个标识前缀的字符串,我执行两次二进制搜索,找到数组中包含以该前缀开头的单词的第一个和最后一个位置:

string [] words = {"aaa","abc","abcd","acd"};
string prefix = "abc";
int firstPosition = Array.BinarySearch<string>(words, prefix);
int lastPosition = Array.BinarySearch<string>(words, prefix + char.MaxValue);
if (firstPosition < 0)
    firstPosition = ~firstPosition;
if (lastPosition < 0)
    lastPosition = ~lastPosition;

运行此代码我得到firstPosition和lastPosition都等于1,而正确的答案是让lastPosition等于3(即指向第一个不匹配的单词)。 BinarySearch方法使用CompareTo方法来比较对象,我发现了

("abc"+char.MaxValue).CompareTo("abc")==0

意味着两个字符串被认为是相等的! 如果我用

更改代码
int lastPosition = Array.BinarySearch<string>(words, prefix + "z");

我得到了正确的答案。 而且我发现了

("abc"+char.MaxValue)==("abc")

正确(根据我的需要)返回false。

你能帮我解释一下CompareTo方法的行为吗?

我希望CompareTo方法的行为类似于==,以便BinarySearch方法为lastPosition返回3。

2 个答案:

答案 0 :(得分:6)

string.CompareTo()进行当前文化比较。在内部,它使用StringComparer.CurrentCulture,而字符串equals-operator执行文化不变的比较。

例如,如果当前文化是“DE”,您将获得与“ss”和“ß”相同的结果:

Console.WriteLine("ss".CompareTo("ß")); // => 0
Console.WriteLine("ss" == "ß"); // => false

你想要的是一种文化不变的比较,你可以使用StringComparer.Ordinal获得:

StringComparer.Ordinal.Compare("ss", "ß"); // => -108
StringComparer.Ordinal.Compare("abc"+char.MaxValue, "abc"); // => 65535

答案 1 :(得分:5)

根据MSDN,不应使用string.CompareTo来检查两个字符串是否相等:

  

CompareTo方法主要用于排序或字母顺序操作。当方法调用的主要目的是确定两个字符串是否相等时,不应使用它。要确定两个字符串是否相等,请调用Equals方法。

要获得您希望的行为,您可以使用接受IComparer<T>的重载:

int lastPosition = Array.BinarySearch<string>(words, prefix + char.MaxValue, 
                                              StringComparer.Ordinal);

这将为-4返回lastPosition,因为数组中没有包含该前缀的字符串。在这种情况下,我不明白为什么你期望3 ...