Compare version numbers without using split function
How do I co开发者_开发技巧mpare version numbers?
For instance:
x = 1.23.56.1487.5
y = 1.24.55.487.2
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;
}
}
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.
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;
}
}
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;
}
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());
}
}
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
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;
}
精彩评论