Compare version numbers without using split function

C#StringCompareVersionVersioning

C# Problem Overview


How do I compare version numbers?

For instance:

x = 1.23.56.1487.5

y = 1.24.55.487.2

C# Solutions


Solution 1 - C#

Can you use the Version class?
https://docs.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;

	}
}

Solution 2 - C#

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.

Solution 3 - C#

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

Solution 4 - C#

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

Solution 5 - C#

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

Solution 6 - C#

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.

    /// <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());
    }

Solution 7 - C#

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSankar MView Question on Stackoverflow
Solution 1 - C#JohnDView Answer on Stackoverflow
Solution 2 - C#AndreasView Answer on Stackoverflow
Solution 3 - C#tooView Answer on Stackoverflow
Solution 4 - C#user3790307View Answer on Stackoverflow
Solution 5 - C#Fabian BiglerView Answer on Stackoverflow
Solution 6 - C#JayView Answer on Stackoverflow
Solution 7 - C#Wilmar AriasView Answer on Stackoverflow