C# 字符串比较不适用于尾部斜杠

C# String Compare not working with trailing slash

在 C# 4.0 中,每当我比较两个尾部有一个或多个斜杠的字符串时,比较都会给出错误的结果:

String a = "1/2.1/";
String b = "1/2/";
if (a.CompareTo(b) > 0)
    MessageBox.Show("Correct: " + a + " > " + b);
else
    MessageBox.Show("Not correct: " + a + " <= " + b);

a = a.TrimEnd('/');
b = b.TrimEnd('/');

if (a.CompareTo(b) > 0)
    MessageBox.Show("Trailing slash removed. Correct: " + a + " > " + b);
else
    MessageBox.Show("Trailing slash removed. Not correct: " + a + " <= " + b);

从词汇上讲,“1/2.1/”在“1/2/”之后,没有太多疑问。

这种行为也发生在其他地方,例如使用 Select 方法对数据表进行排序。

我是不是做错了什么?或者这是 .Net 中的错误? 它甚至不应该与文化特定信息等有任何关系,因为斜线是最基本的美国 ASCII 字符集的一部分。

在比较 SQL 服务器 hierarchyID 时,我 运行 喜欢这个。很容易解决,但这是一个有点令人惊讶的问题。

如果我在 C 中的旧技能没有让我失望,我认为 CompareTo 会逐个字符地减去字符的整数值,直到结果不为零。

在前 3 个相同的字符之后,CompareTo 查看第四个字符,这是第一个字符串的点和第二个字符串的斜线。

点字符的整数值为46,斜杠的整数值为47,46-47返回-1,所以"1/2.1/"小于"1/2/"。

Lexically speaking, "1/2.1/" comes after "1/2/", and there is not much question about that.

为什么会在后面呢?在 ASCII chart 上,/ 紧跟在 . 之后。

给定以下两个字符串,在到达第 4 个字符之前它们是相等的。然后比较/./更大。所以您看到的结果 (a < b) 实际上是正确的。

1/2.1/
1/2/

调用 TrimEnd() 后,您最终得到两个不同的字符串,其中和 a > b.

1/2.1
1/2

如果数字右对齐,您可以比较包含数字的字符串:

01/02.00/
01/02.10/
01/10.00/

如果这不可能,请考虑为您的数字创建一个类型

public class ChapterNumber :  IComparable<ChapterNumber>
{
    private readonly decimal[] _number;

    public ChapterNumber(params decimal[] number)
    {
        _number = number;
    }

    public int CompareTo(T obj)
    {
        var other = obj as ChapterNumber;
        if (other == null) {
            return +1;
        }
        int len = Math.Min(_number.Length, other._number.Length);
        for (int i = 0; i < len; i++) {
            int result = _number[i].CompareTo(other._number[i]);
            if (result != 0) {
                return result;
            }
        }
        return _number.Length.CompareTo(other._number.Length);
    }

    public override ToString()
    {
        return String.Join('/', _number) + "/";
    }
}

用法:

var a = new ChapterNumber(1, 2.1m);
var b = new ChapterNumber(1, 2);
if (a.CompareTo(b) > 0) {
    ...
}