ASCII比较和字符串比较的区别

8

我使用C#编程语言。当我比较两个char值时,得到的输出是正确的。例如:

'-'.CompareTo('!') //Its sending me positive value 12

意思是 '-' > '!'true

但是当我比较两个相同值的字符串时,结果却不同

"-".CompareTo("!") //Its sending me negative value -1

意味着 "-" > "!"false

有人可以解释一下为什么是这样吗?两种情况都不应该是真的吗?


1
CompareTo 用于排序,而不是(必然)用于检查相等性。如果 CompareTo 返回零,则认为实例是“相等的”。有关详细信息,请参阅 Char.CompareToString.CompareTo - Corak
Char.CompareTo : 此方法执行的比较基于此实例和 value 的编码值,而不是它们的词典特征。 - Corak
@Corak - 我正在为字符串实现二分查找方法。因此,我需要一个已排序的数组。你觉得我应该使用 CompareTo() 还是自己编写比较方法? - Arnab
2
@Arnab 要小心进行自定义字符串比较,除非你真正了解不同文化之间的差异(或者你只处理单一文化)。字符比较(如你所见)很容易产生误导。 - Adriano Repetti
1
"取决于" ... 无论如何,当比较“字符串”时,您可能不希望使用char逻辑。问题是您想如何排序。应该是文化感知的、文化无关的还是词典独立的? String.CompareToString.CompareToOrdinal是否按您所需进行排序?然后使用它们,否则构建自己的排序逻辑。-- 您可能还想查看使用StringComparison进行比较使用CultureInfo进行比较 - Corak
3个回答

10

String的Compare方法是与文化相关的。这就是为什么你会得到不同的结果。相反,使用string.CompareOrdinal进行比较,它是逐字节比较的。

var v = '-'.CompareTo('!');//12
var s = string.CompareOrdinal("-", "!");//12

在.NET Framework中使用字符串的最佳实践


我正在实现一个字符串的二分查找方法。因此,我需要一个已排序的数组。你认为使用CompareTo()会有任何问题,还是应该使用CompareOrdinal? - Arnab
这取决于你的结果需要如何,如果你需要文化相关的比较,请使用 CompareTo。还有其他比较选项,它们是 InvariantCulture 和忽略大小写的变体。请参考我提供的链接并选择最适合你的选项。 - Sriram Sakthivel

4
这个比较 '-'.CompareTo('!') 将执行一个 排序比较,将比较数值化的UTF-16编码值(4533)。
字符串比较 "-".CompareTo("!") 是不同的,它将执行一个 区域敏感比较。也就是说,无论数值如何,字符将按照当前区域设置下的排序规则进行排序。
你可以尝试使用排序比较对字符串进行比较:
String.CompareOrdinal("-", "!")

那将对字符串执行一个序数比较,然后你将得到相同的结果 (12)。
如果你需要进行真正的区域设置感知比较,则无法对Char执行此操作(在这种情况下只需转换为string),因为排序顺序可能会受到你正在比较的字符前面和/或后面的影响,单个字符可能不是一个字形(并且排序可能不适用)。一个例子:在捷克语中,C排在H之前,然后你期望"ch".CompareTo("h") == -1...错了,"ch"是一个二合字,它介于HI之间,那么"ch".CompareTo("h") == 1!更多信息请参见这篇更详细的文章
序数比较之所以不同,仅仅是因为其源自ASCII(我尝试过的每种文化都返回了该排序的相同结果)。他们为了兼容性(和更容易迁移到Unicode)而保留了ASCII排序,但对于字符串比较,他们必须遵守文化规则。
这种情况的更常见的例子是大写/小写字符(注意'"以执行序数和区域设置感知比较):
'A'.CompareTo('a') != "A".CompareTo("a")

如果你正在进行文本搜索,我强烈建议你不要直接使用Char比较,除非你了解文化问题(排序)和Unicode细节(代理和编码)。


1
这是由于在Char和String类中,实现IComparable接口的CompareTo方法不同导致的。

Char.cs

public int CompareTo(Char value) {
      return (m_value-value);
}

String.cs

public int CompareTo(String strB) {
    return CultureInfo.CurrentCulture.CompareInfo.Compare(this, strB, 0);
}

其中逻辑是文化感知比较,依赖于内部的InternalCompareString

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接