在.Net中的字符串比较:"+"与"-"的区别

14

我一直以为.NET根据当前文化对字符串进行词典排序。但是当其中一个字符串以'-'结尾时,会发生一些奇怪的事情:

"+".CompareTo("-")
Returns: 1

"+1".CompareTo("-1")
Returns: -1

我试过所有的文化,包括不变的文化,但我还是无法得到一致的字符顺序。有人能解释一下发生了什么,以及如何在当前语言环境下获得一致的逐字符排序吗?


对于 "x+".CompareTo("x-")"x+1".CompareTo("x-1"),结果相同。 - H H
5个回答

10

尝试将此更改为

string.Compare("+", "-", StringComparison.Ordinal); // == -2
string.Compare("+1", "-1", StringComparison.Ordinal); // == -2

1
谢谢Anton,但是Ordinal表示旧的好的ASCII排序方式,其中所有大写字母都排在小写字母前面。string.Compare("a", "Z", StringComparison.Ordinal); 7在我的语言环境中,区分大小写的排序方式类似于'a'<'A'<'ä'<'Ä'<...<'z'<'Z',但我没有找到直接访问它的方式。 - jmster
jmster:为什么不自己写排序算法?你只关心数字吗? - Noon Silk
我已经编写了自己的方法,但是在底部我需要一些按照本地规则比较字符的方法。我不想手动编写区域设置,应该可以从Windows获取。 - jmster

7

对于任何特定的区域设置,不一定存在连续的逐字排序。

来自MSDN文档

例如,某种文化可能指定将某些字符组合视为单个字符,或者以特定方式比较大写和小写字符,或者一个字符的排序顺序取决于在其之前或之后的字符。

确保连续的逐字排序的唯一方法是使用序数比较,如Anton's answer中所示。


这解释了问题。我唯一想知道的是,为什么他们需要为 ASCII 减号这样的通用字符引入如此神奇的处理方式? - jmster
@jmster:我猜测单独的 "+" 和 "-" 字符并没有实际意义,所以在这种情况下会进行一次序数比较,其中 "+"(代码 43)被解释为小于"-"(代码 45)。但是,当 "+" 和 "-" 字符前缀一个数字时,它们就会有意义,在这种情况下,会进行"语义"和/或数值比较,其中 "+1" 大于 "-1"。 - LukeH
实际上恰恰相反,.NET使用ASCII排序来得出"+1"小于"-1"的结论,但在最后一个位置,减号神奇地变成连字符,因此"-"被排序在"\a"(响铃)和空格之间的某个位置。 - jmster
@jmster:是的,你说得对。我的猜测是错误的。我认为文档中的摘录仍然适用,但我不知道在这种情况下适用于不同比较的特定逻辑是什么。 - LukeH

3
        string.Compare("+", "-");
        string.Compare("+", "-", StringComparison.CurrentCulture);
        string.Compare("+", "-", StringComparison.InvariantCulture);
        string.Compare("+", "-", StringComparison.InvariantCultureIgnoreCase);

        // All Pass

这两个值相等是因为考虑了语言大小写的情况。

修复方法:

将不变比较替换为顺序比较。这意味着决策基于简单的字节比较,忽略大小写或由文化参数化的等效表。

参考资料:使用顺序比较

string.Compare("+", "-", StringComparison.Ordinal); // 失败


2

在IT技术中,你可能需要使用真正的减号,Unicode代码点为\u2212。 编程中使用的减号(\u002d)是“连字符”,其排序顺序是上下文敏感的,因为它经常用作连字符。 有关各种破折号的更多信息,请参见此文章


1
你的观察完全正确,Unicode 的人似乎更清楚每个字符应该如何使用。问题在于用户不记得 Unicode 编号,而是使用他们在键盘上看到的字符。 - jmster
排版和编程语言仍然是两个世界。也许有一天会改变,但需要一段时间。有很多Alt+键盘快捷键可用于输入这些Unicode代码点,具有讽刺意味的是减号没有。 - Hans Passant

0
使用CompareOrdinal。例如:
String.CompareOrdinal("+1","-1");
-2
String.CompareOrdinal("+","-");
-2

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