将数值作为字符串进行比较

本文关键字:比较 字符串 | 更新日期: 2023-09-27 18:24:57

我有一个方法,它得到两个字符串。这些字符串可以同时包含数字、ASCII字符或两者。

算法是这样工作的:

  1. 将两个字符串拆分为字符数组A和B
  2. 尝试将元素Ai和Bi解析为int
  3. 比较元素Ai和元素Bi,如果是整数,则使用直接比较,如果是字符,则使用顺序字符串比较
  4. 根据结果做事

现在,我想知道:我真的需要将元素解析为int吗?我可以简单地比较有序字符串比较中的每个元素,得到相同的结果,对吧?这里的性能含义是什么?解析和正常比较比顺序字符串比较快吗?速度慢吗?

我的假设(使用顺序字符串比较而不是解析和比较)正确吗?

以下是有问题的方法:

internal static int CompareComponentString(this string componentString, string other)
{
    bool componentEmpty = string.IsNullOrWhiteSpace(componentString);
    bool otherEmtpy = string.IsNullOrWhiteSpace(other);
    if (componentEmpty && otherEmtpy)
    {
        return 0;
    }
    if (componentEmpty)
    {
        return -1;
    }
    if (otherEmtpy)
    {
        return 1;
    }
    string[] componentParts = componentString.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
    string[] otherParts = other.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
    for (int i = 0; i < Math.Min(componentParts.Length, otherParts.Length); i++)
    {
        string componentChar = componentParts[i];
        string otherChar = otherParts[i];
        int componentNumVal, otherNumVal;
        bool componentIsNum = int.TryParse(componentChar, out componentNumVal);
        bool otherIsNum = int.TryParse(otherChar, out otherNumVal);
        if (componentIsNum && otherIsNum)
        {
            if (componentNumVal.CompareTo(otherNumVal) == 0)
            {
                continue;
            }
            return componentNumVal.CompareTo(otherNumVal);
        }
        else
        {
            if (componentIsNum)
            {
                return -1;
            }
            if (otherIsNum)
            {
                return 1;
            }
            int comp = string.Compare(componentChar, otherChar, StringComparison.OrdinalIgnoreCase);
            if (comp != 0)
            {
                return comp;
            }
        }
    }
    return componentParts.Length.CompareTo(otherParts.Length);
}

这是可能使用的字符串。我可能只添加部分,在之后使用减号。

  • 1.0.0-alpha
  • 1.0.0-α1
  • 1.0.0-alpha.beta
  • 1.0.0-测试版2

将数值作为字符串进行比较

使用此方法,您可以为每个字符串创建一个比较字符串。这些字符串可以通过简单的字母数字比较进行比较。

假设:

  • 字符串中有一个分隔公共部分和独立部分的减号
  • 之前,减号总是三个整数值除以一个点的子字符串
  • 这些整数值不高于999(查看变量"MaxWidth1")
  • 后面的减号是另一个子串,由几个部分组成,也被一个点分割
  • 第二个子字符串的部分可以是数字或字母数字,最大宽度为7(参见"MaxWidth2")
  • 第二个子字符串最多由5部分组成(MaxIndivParts)

把这种方法放在你想放的地方:

public string VersionNumberCompareString(string versionNumber, int MaxWidth1=3, int MaxWidth2=7,int MaxIndivParts=5){
    string result = null;
    int posMinus = versionNumber.IndexOf('-');
    string part1 = versionNumber.Substring(0, posMinus);
    string part2 = versionNumber.Substring(posMinus+1);
    var integerValues=part1.Split('.');
    result = integerValues[0].PadLeft(MaxWidth1, '0');
    result += integerValues[1].PadLeft(MaxWidth1, '0');
    result += integerValues[2].PadLeft(MaxWidth1, '0');
    var alphaValues = part2.Split('.');
    for (int i = 0; i < MaxIndivParts;i++ ) {
        if (i <= alphaValues.GetUpperBound(0)) {
            var s = alphaValues[i];
            int casted;
            if (int.TryParse(s, out casted)) //if int: treat as number
                result += casted.ToString().PadLeft(MaxWidth2, '0');
            else //treat as string
                result += s.PadRight(MaxWidth2, ' ');
    }
    else
        result += new string(' ', MaxWidth2);
}
return result;    }

你这样称呼它:

var s1 = VersionNumberCompareString("1.3.0-alpha.1.12"); 
//"001003000alpha  00000010000012              "
var s2 = VersionNumberCompareString("0.11.4-beta");      
//"000011004beta                               "
var s3 = VersionNumberCompareString("2.10.11-beta.2");   
//"002010011beta   0000002                     "                        

注意最后的"符号。所有字符串的长度都相同!

希望这能帮助。。。

这是ascii字符串的.net比较逻辑-

  private unsafe static int CompareOrdinalIgnoreCaseHelper(String strA, String strB)
    {
        Contract.Requires(strA != null);
        Contract.Requires(strB != null);
        Contract.EndContractBlock();
        int length = Math.Min(strA.Length, strB.Length);
        fixed (char* ap = &strA.m_firstChar) fixed (char* bp = &strB.m_firstChar)
        {
            char* a = ap;
            char* b = bp;
            while (length != 0) 
            {
                int charA = *a;
                int charB = *b;
                Contract.Assert((charA | charB) <= 0x7F, "strings have to be ASCII");
                // uppercase both chars - notice that we need just one compare per char
                if ((uint)(charA - 'a') <= (uint)('z' - 'a')) charA -= 0x20;
                if ((uint)(charB - 'a') <= (uint)('z' - 'a')) charB -= 0x20;
                //Return the (case-insensitive) difference between them.
                if (charA != charB)
                    return charA - charB;
                // Next char
                a++; b++;
                length--;
            }
            return strA.Length - strB.Length;
        }
    }

话虽如此,除非你有一个严格的性能常数,否则我会说,如果你从已经实现的&经过测试的功能,最好重用它,而不是重新发明轮子。它在实现、单元测试、调试和维护方面节省了大量时间;错误修复时间&有助于保持软件简单。