【问题标题】:C# String Compare not working with trailing slashC#字符串比较不适用于斜杠
【发布时间】:2015-06-17 19:57:27
【问题描述】:

在 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 Server 层次 ID 时遇到了这个问题。这很容易解决,但这是一个有点令人惊讶的问题。

【问题讨论】:

  • . 是 0x2e,/ 是 0x2f。 . 是第一位的。您的问题正是在您认为理所当然的假设中:“1/2.1/ 出现在 1/2/ 之后,对此没有太多疑问。”跨度>
  • 请注意,您正在使用文化敏感比较。很少有人了解 Unicode 比较规则。您会发现许多令人惊讶的行为。

标签: c# c#-4.0


【解决方案1】:

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

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) {
    ...
}

【讨论】:

    【解决方案2】:

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

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

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

    1/2.1/
    1/2/
    

    在调用TrimEnd() 之后,你会得到两个不同的字符串 where 和 a &gt; b

    1/2.1
    1/2
    

    【讨论】:

    • 谢谢 - 当然你是对的,C# 执行逐个字符的代码点比较。被 SQL Server hierarchyID(字符串转换的)值严格按顺序排列的常见说法搞砸了——这就是这些类型的字符串的来源。好吧,那么它们不是按顺序排列的。
    • 这适用于字符串较长的情况:1/2.1/1/1/2/1/,或者如果它们的第一个数字不同:1.1/2/1/2/
    【解决方案3】:

    如果我在 C 方面的老技能没有让我失望,我认为 CompareTo 执行一个字符一个字符地减去字符的整数值,直到结果不为零。

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

    点字符的整数值为46,而斜杠的整数值为47,46-47返回-1,因此“1/2.1/”小于“1/2/”。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-08
      • 1970-01-01
      • 2015-10-26
      • 1970-01-01
      • 2013-01-22
      • 1970-01-01
      • 1970-01-01
      • 2015-03-27
      相关资源
      最近更新 更多