177

How do I compare version numbers?

For instance:

x = 1.23.56.1487.5

y = 1.24.55.487.2

4
  • 5
    What do you want the result to be? Commented Sep 27, 2011 at 11:12
  • 6
    a version with 5 parts? If you were using the typical 4 part version you could use the System.Version class, which includes methods to compare versions and parse the version string Commented Sep 27, 2011 at 11:14
  • 1
    What are the types of x and y? Commented Sep 27, 2011 at 11:14
  • 7
    Whenever someone says "Don't use X, Y or Z", it always makes me wonder why. Why do you not want to use the split function? The split function seems like a good way to do this if you aren't going to use the System.Version class. Commented Sep 27, 2011 at 11:35

7 Answers 7

398

Can you use the Version class?
https://learn.microsoft.com/en-us/dotnet/api/system.version

It has an IComparable interface. Be aware this won't work with a 5-part version string like you've shown (is that really your version string?). Assuming your inputs are strings, here's a working sample with the normal .NET 4-part version string:

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;

    }
}
Sign up to request clarification or add additional context in comments.

5 Comments

Only if the version consists from 2-4 parts
@dev_Boston only one exception...just do with these values v1=1.0001 and v2=1.1 .it gives me equal.
Yes, the version strings are not decimal strings, and prepending zeroes to a portion of the version number is irrelevant. In other words, "00001" is equal to "1" in the 2nd part of the version string.
You can compare more readably as Version.Parse(v1) < Version.Parse(v2), because operator >(Version v1, Version v2) is implemented.
Be aware that Version.Parse("6.0.0") is less than (<) Version.Parse("6.0.0.0") (i.e. are NOT equal). Debug.Assert(new Version("6.0.0") < new Version("6.0.0.0"));
14

If you can live with the major.minor.build.revision scheme you could use the .Net Version class. Otherwise you'd have to implement some kind of parsing from left to right and continuing until you have a difference or return that two versions are equal.

Comments

7

In addition to @JohnD 's answer there might be a need to compare only partial version numbers without using Split('.') or other string <-> int conversion bloat. I've just written an extension method CompareTo with 1 additional argument - number of significant parts of version number to compare (between 1 and 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; 
    }
}

Comments

5
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;
    }

1 Comment

Beware that this would return equals for compareVersion("1.3", "1.3.1")
2

I found this algoritm on internet seems to work well.

//https://www.geeksforgeeks.org/compare-two-version-numbers/amp/

static int versionCompare(string v1, string v2)
    {
        // vnum stores each numeric
    
        // part of version
    
        int vnum1 = 0, vnum2 = 0;
    
        // loop until both string are
        // processed
    
        for (int i = 0, j = 0; (i < v1.Length || j < v2.Length);)
    
        {
            // storing numeric part of
            // version 1 in vnum1
            while (i < v1.Length && v1[i] != '.')
            {
    
                vnum1 = vnum1 * 10 + (v1[i] - '0');
    
                i++;
            }
            // storing numeric part of
    
            // version 2 in vnum2
    
            while (j < v2.Length && v2[j] != '.')
            {
                vnum2 = vnum2 * 10 + (v2[j] - '0');
                j++;
            }
            if (vnum1 > vnum2)
                return 1;
    
            if (vnum2 > vnum1)
                return -1;
    
            // if equal, reset variables and
    
            // go for next numeric part
            vnum1 = vnum2 = 0;
            i++;
            j++;
        }
    
        return 0;
    
    }

Comments

2

Here's mine. I needed to compare some wacky version strings like "3.2.1.7650.b40" versus "3.10.1" so I couldn't use the VersionInfo object as suggested above. This is quick and dirty so ding me for style. I did also provide a short function to test it.

using System;
                    
public class Program
{
    public static void Main()
    {
        Test_CompareVersionStrings();
    }
    
    /// <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
            
            string v1Token = v1parts[i];
            string v2Token = v2parts[i];
            
            int x;
            bool v1Numeric = int.TryParse(v1Token, out x);
            bool v2Numeric = int.TryParse(v2Token, out x);
            
            // handle scenario {"2" versus "20"} by prepending zeroes, e.g. it would become {"02" versus "20"}
            if (v1Numeric && v2Numeric) {
                while (v1Token.Length < v2Token.Length)
                    v1Token = "0" + v1Token;
                while (v2Token.Length < v1Token.Length)
                    v2Token = "0" + v2Token;
            }

            rc = String.Compare(v1Token, v2Token, StringComparison.Ordinal);
            //Console.WriteLine("v1Token=" + v1Token + " v2Token=" + v2Token + " rc=" + rc);
            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;
    }
    
    private static int _CompareVersionStrings(string v1, string v2)
    {
        int rc = CompareVersionStrings(v1, v2);
        Console.WriteLine("Compare v1: " + v1 + "  v2: " + v2 + "  result: " + rc);
        return rc;
    }

    // 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"));
        allPass &= (-1 == _CompareVersionStrings("1.8.0", "20.0.0.0"));
        allPass &= (-1 == _CompareVersionStrings("5.6.0.788.2", "20.0.0.0"));

        // 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")); 
        allPass &= (1 == _CompareVersionStrings("20.0.0.0", "5.6.0.788.2"));

        Console.WriteLine("allPass = " + allPass.ToString());
    }   
}

2 Comments

Wrong. See ("1.8.0","20.0.0.0") = -1 and ("5.6.0.788.2","20.0.0.0") = 1
Thanks for the catch. I corrected it above and also created a dotnetfiddle: dotnetfiddle.net/ehGhJT
1

If for some reason you are not allowed to use the compare-method of the Version directly (e.g. in a client-server scenario), another approach is to extract a long number from the version and then compare the numbers with each other. However, the number needs to have the following format: Two digits for Major, Minor and Revision and four for Build.

How to extract the version number:

var version = Assembly.GetExecutingAssembly().GetName().Version;

long newVersion = version.Major * 1000000000L + 
                   version.Minor * 1000000L + 
                   version.Build * 1000L + 
                   version.Revision;

And then somewhere else you can just compare:

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

Note: the installedVersion is a previously extracted long number

2 Comments

To give all digits 3 places, the code should actually be : "version.Major * 1000000000L + version.Minor * 1000000L + version.Build * 1000L + version.Revision"
@StefHeyenrath That is correct, feel free to adjust the above code to your own needs.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.