不使用拆分功能比较版本号

Posted

技术标签:

【中文标题】不使用拆分功能比较版本号【英文标题】: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 函数似乎是一个很好的方法。 【参考方案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());
    

【讨论】:

以上是关于不使用拆分功能比较版本号的主要内容,如果未能解决你的问题,请参考以下文章

版本号对比方案及参考代码(Objective-C,Java,JavaScript)

JS 实现版本号比较功能

版本号的比较

Android Gradle 插件Gradle 依赖管理 ⑤ ( dependencies 依赖项拆分 | 依赖组 | 依赖名称 | 依赖版本号 | 动态指定依赖版本号 | 使用命令行查看模块 )

Java实现比较版本号

Linux获取so/ko文件版本号教程