C# 为什么(";abc";&x2B;char.MaxValue)。比较(";abc";)==0?

C# 为什么(";abc";&x2B;char.MaxValue)。比较(";abc";)==0?,c#,C#,我有一个排序的字符串数组。 给定标识前缀的字符串,我将执行两次二进制搜索,以查找数组中包含以该前缀开头的单词的第一个和最后一个位置: string [] words = {"aaa","abc","abcd","acd"}; string prefix = "abc"; int firstPosition = Array.BinarySearch<string>(words, prefix); int lastPosition = Array.BinarySearch<stri

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

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;
这意味着两个字符串被视为相等! 如果我用

int lastPosition = Array.BinarySearch<string>(words, prefix + "z");
正确(关于我的需要)返回false

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

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

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

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

要获得所需的行为,您可以使用接受
IComparer
的重载:

int lastPosition=Array.BinarySearch(单词,前缀+char.MaxValue,
序列比较器);
这将为
lastPosition
返回
-4
,因为数组中没有带有该前缀的字符串。我不明白为什么您希望
3
在这种情况下…

string.CompareTo()
进行当前区域性比较。在内部,它使用
StringComparer.CurrentCulture
,而string equals运算符执行区域性不变比较

例如,如果当前区域性为“DE”,您将获得与“ss”和“ß”相同的结果:

您需要的是区域性不变比较,您可以使用
StringComparer.Ordinal

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

无论
BinarySearch
在这里使用什么(例如
string.IndexOf
CompareTo
)。它忽略Char.MaxValue的十六进制值。在中搜索
ignore
,您会发现这是可能的。From:“CompareTo方法设计用于排序或字母排序操作。当方法调用的主要目的是确定两个字符串是否等效时,不应使用它。若要确定两个字符串是否等效,请调用Equals方法。”这段代码是一个更通用的函数的一部分,该函数对不同的数据类型执行“范围”搜索,前提是搜索的对象实现IComparable。出于这个原因,我认为二进制搜索是一个灵活的解决方案,而使用诸如前缀树之类的文本专用数据结构并不适合这个目的。我认为一个可能的解决方案是将字符串类型封装到一个类型中,在其CompareTo方法中实现“正确”比较。问题是调用CompareTo方法的不是我的代码,而是Array.BinarySearch方法。
if(lastPosition<0)lastPosition=~lastPosition将-4转换为3。StringComparer.Ordinal是正确的比较器。现在我必须决定如何在不破坏通用灵活性的情况下将其插入到实际代码中。@Esuli:啊,好的。你想在手术后得到
3
。上帝回答。作为补充:OP可能希望使用
StringComparer.OrdinalIgnoreCase.Compare(…,…)
String.Compare(…,…,stringcomparation.OrdinalIgnoreCase)
来实现区域性不变、不区分大小写的比较。@Abbondanza。还有
string.CompareOrdinal(“abc\uFFFF”,“abc”)
。但是由于询问者调用了
BinarySearch
方法,因此他应该传递名为
StringComparer.Ordinal
IComparer
实例。
("abc"+char.MaxValue)==("abc")
int lastPosition = Array.BinarySearch<string>(words, prefix + char.MaxValue, 
                                              StringComparer.Ordinal);
Console.WriteLine("ss".CompareTo("ß")); // => 0
Console.WriteLine("ss" == "ß"); // => false
StringComparer.Ordinal.Compare("ss", "ß"); // => -108
StringComparer.Ordinal.Compare("abc"+char.MaxValue, "abc"); // => 65535