不使用拆分功能比较版本号
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的类型有哪些? 每当有人说“不要使用X
、Y
或Z
”时,我总是想知道为什么。为什么不想使用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) < Version.Parse(v2)
比作更具可读性,因为operator >(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)
Android Gradle 插件Gradle 依赖管理 ⑤ ( dependencies 依赖项拆分 | 依赖组 | 依赖名称 | 依赖版本号 | 动态指定依赖版本号 | 使用命令行查看模块 )