【问题标题】:Compare version numbers without using split function不使用拆分功能比较版本号
【发布时间】:2011-11-25 22:59:18
【问题描述】:

如何比较版本号?

例如:

x = 1.23.56.1487.5

y = 1.24.55.487.2

【问题讨论】:

  • 你希望结果是什么?
  • 有 5 个部分的版本?如果您使用的是典型的 4 部分版本,则可以使用 System.Version 类,其中包括比较版本和解析版本字符串的方法
  • x和y的类型有哪些?
  • 每当有人说“不要使用XYZ”时,我总是想知道为什么。为什么不想使用split 函数?如果您不打算使用 System.Version 类,split 函数似乎是一个很好的方法。

标签: c# string compare version versioning


【解决方案1】:

你可以使用Version类吗?
https://docs.microsoft.com/en-us/dotnet/api/system.version

它有一个IComparable 接口。请注意,这不适用于您展示的 5 部分版本字符串(这真的是您的版本字符串吗?)。假设您的输入是字符串,这是一个带有正常 .NET 4 部分版本字符串的工作示例:

static class Program
{
    static void Main()
    {
        string v1 = "1.23.56.1487";
        string v2 = "1.24.55.487";

        var version1 = new Version(v1);
        var version2 = new Version(v2);

        var result = version1.CompareTo(version2);
        if (result > 0)
            Console.WriteLine("version1 is greater");
        else if (result < 0)
            Console.WriteLine("version2 is greater");
        else
            Console.WriteLine("versions are equal");
        return;

    }
}

【讨论】:

  • 仅当版本由 2-4 个部分组成时
  • @dev_Boston 只有一个例外......只需使用这些值 v1=1.0001 和 v2=1.1 即可。它给了我平等。
  • 是的,版本字符串不是十进制字符串,在版本号的一部分前加零是无关紧要的。换句话说,“00001”在版本字符串的第二部分等于“1”。
  • 您可以将Version.Parse(v1) &lt; Version.Parse(v2) 比作更具可读性,因为operator &gt;(Version v1, Version v2) 已实现。
  • 请注意 Version.Parse("6.0.0") 小于 (Debug.Assert(new Version("6.0.0") < new Version("6.0.0.0"));
【解决方案2】:

如果您可以使用major.minor.build.revision 方案,您可以使用.Net Version 类。否则,您必须从左到右执行某种解析并继续执行,直到您有差异或返回两个版本相等。

【讨论】:

    【解决方案3】:

    除了@JohnD 的答案之外,可能需要只比较部分版本号而不使用 Split('.') 或其他字符串 int 转换膨胀。我刚刚编写了一个扩展方法 CompareTo,带有 1 个附加参数 - 要比较的版本号的重要部分的数量(在 1 和 4 之间)。

    public static class VersionExtensions
    {
        public static int CompareTo(this Version version, Version otherVersion, int significantParts)
        {
            if(version == null)
            {
                throw new ArgumentNullException("version");
            }
            if(otherVersion == null)
            {
                return 1;
            }
    
            if(version.Major != otherVersion.Major && significantParts >= 1)
                if(version.Major > otherVersion.Major)
                    return 1;
                else
                    return -1;
    
            if(version.Minor != otherVersion.Minor && significantParts >= 2)
                if(version.Minor > otherVersion.Minor)
                    return 1;
                else
                    return -1;
    
            if(version.Build != otherVersion.Build && significantParts >= 3)
                if(version.Build > otherVersion.Build)
                    return 1;
                else
                    return -1;
    
            if(version.Revision != otherVersion.Revision && significantParts >= 4)
                if(version.Revision > otherVersion.Revision)
                    return 1;
                else
                    return -1;
    
            return 0; 
        }
    }
    

    【讨论】:

      【解决方案4】:
      public int compareVersion(string Version1,string Version2)
          {
              System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(@"([\d]+)");
              System.Text.RegularExpressions.MatchCollection m1 = regex.Matches(Version1);
              System.Text.RegularExpressions.MatchCollection m2 = regex.Matches(Version2);
              int min = Math.Min(m1.Count,m2.Count);
              for(int i=0; i<min;i++)
              {
                  if(Convert.ToInt32(m1[i].Value)>Convert.ToInt32(m2[i].Value))
                  {
                      return 1;
                  }
                  if(Convert.ToInt32(m1[i].Value)<Convert.ToInt32(m2[i].Value))
                  {
                      return -1;
                  }               
              }
              return 0;
          }
      

      【讨论】:

      • 请注意,这将返回等于 compareVersion("1.3", "1.3.1")
      【解决方案5】:

      如果由于某种原因不允许您直接使用版本的比较方法(例如在客户端-服务器场景中),另一种方法是从版本中提取一个长数字,然后将这些数字相互比较. 但是,该数字需要具有以下格式:Major、Minor 和 Revision 两位数,Build 两位数。

      如何提取版本号:

      var version = Assembly.GetExecutingAssembly().GetName().Version;
      
      long newVersion = version.Major * 1000000000L + 
                         version.Minor * 1000000L + 
                         version.Build * 1000L + 
                         version.Revision;
      

      然后你可以在其他地方进行比较:

      if(newVersion > installedVersion)
      {
        //update code
      }
      

      注意:installedVersion 是之前提取的长数字

      【讨论】:

      • 要给所有数字3位,代码实际上应该是:“version.Major * 1000000000L + version.Minor * 1000000L + version.Build * 1000L + version.Revision”
      • @StefHeyenrath 说得对,您可以根据自己的需要随意调整上述代码。
      【解决方案6】:

      这是我的。我需要比较一些古怪的版本字符串,比如“3.2.1.7650.b40”和“3.10.1”,所以我不能使用上面建议的 VersionInfo 对象。 这又快又脏,所以让我很喜欢。我还提供了一个简短的函数来测试它。

          /// <summary>
          /// Compare two version strings, e.g.  "3.2.1.0.b40" and "3.10.1.a".
          /// V1 and V2 can have different number of components.
          /// Components must be delimited by dot.
          /// </summary>
          /// <remarks>
          /// This doesn't do any null/empty checks so please don't pass dumb parameters
          /// </remarks>
          /// <param name="v1"></param>
          /// <param name="v2"></param>
          /// <returns>
          /// -1 if v1 is lower version number than v2,
          /// 0 if v1 == v2,
          /// 1 if v1 is higher version number than v2,
          /// -1000 if we couldn't figure it out (something went wrong)
          /// </returns>
          private static int CompareVersionStrings(string v1, string v2)
          {
              int rc = -1000;
      
              v1 = v1.ToLower();
              v2 = v2.ToLower();
              
              if (v1 == v2)
                  return 0;
      
              string[] v1parts = v1.Split('.');
              string[] v2parts = v2.Split('.');
      
              for (int i = 0; i < v1parts.Length; i++)
              {
                  if (v2parts.Length < i+1)
                      break; // we're done here
      
                  rc = String.Compare(v1parts[i], v2parts[i], StringComparison.Ordinal);
                  if (rc != 0)
                      break;
              }
      
              if (rc == 0)
              {
                  // catch this scenario: v1="1.0.1" v2="1.0"
                  if (v1parts.Length > v2parts.Length)
                      rc = 1; // v1 is higher version than v2
                  // catch this scenario: v1="1.0" v2="1.0.1"
                  else if (v2parts.Length > v1parts.Length)
                      rc = -1; // v1 is lower version than v2
              }
      
              if (rc == 0 || rc == -1000)
                  return rc;
              else
                  return rc < 0 ? -1 : 1;
          }
      
          // for debugging
          private static void Test_CompareVersionStrings()
          {
              bool allPass = true;
      
              // should be equal
              allPass &= (0 == CompareVersionStrings("1", "1"));
              allPass &= (0 == CompareVersionStrings("1.1", "1.1"));
              allPass &= (0 == CompareVersionStrings("3.3.a20", "3.3.A20"));
      
              // v1 should be lower
              allPass &= (-1 == CompareVersionStrings("1", "2"));
              allPass &= (-1 == CompareVersionStrings("1.0", "1.0.1"));
              allPass &= (-1 == CompareVersionStrings("1.0", "1.1"));
              allPass &= (-1 == CompareVersionStrings("1.0.0.3", "1.1"));
              allPass &= (-1 == CompareVersionStrings("1.2.3.4", "1.2.3.4b"));
              allPass &= (-1 == CompareVersionStrings("1.2.3.4", "1.2.3.4.b"));
      
              // v1 should be higher
              allPass &= (1 == CompareVersionStrings("2", "1"));
              allPass &= (1 == CompareVersionStrings("1.0.1", "1.0"));
              allPass &= (1 == CompareVersionStrings("1.1", "1.0"));
              allPass &= (1 == CompareVersionStrings("1.1", "1.0.0.3"));
              allPass &= (1 == CompareVersionStrings("1.2.3.4b", "1.2.3.4"));
              allPass &= (1 == CompareVersionStrings("1.2.3.4.b", "1.2.3.4"));
      
              System.Diagnostics.Debug.WriteLine("AllPass = " + allPass.ToString());
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-26
        • 2012-06-10
        • 2013-09-06
        • 1970-01-01
        • 2019-12-01
        • 2016-04-24
        相关资源
        最近更新 更多