5

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

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。

4

2 回答 2

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
于 2012-11-20T11:15:00.597 回答
5

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

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

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

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

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

于 2012-11-20T11:10:58.470 回答