是否有比较版本号的标准习语?我不能直接使用String compareTo,因为我还不知道点释放的最大数量是多少。我需要比较版本,并有以下保持正确:
1.0 < 1.1
1.0.1 < 1.1
1.9 < 1.10
是否有比较版本号的标准习语?我不能直接使用String compareTo,因为我还不知道点释放的最大数量是多少。我需要比较版本,并有以下保持正确:
1.0 < 1.1
1.0.1 < 1.1
1.9 < 1.10
当前回答
想知道为什么每个人都假设版本只由整数组成-在我的情况下,它不是。
为什么要重新发明轮子(假设版本遵循Semver标准)
首先通过Maven安装https://github.com/vdurmont/semver4j
然后使用这个库
Semver sem = new Semver("1.2.3");
sem.isGreaterThan("1.2.2"); // true
其他回答
对于我的项目,我使用我的公共版本库https://github.com/raydac/commons-version 它包含两个辅助类-用于解析版本(解析后的版本可以与另一个版本对象进行比较,因为它是可比的)和VersionValidator,它允许检查一些表达式的版本,如!=ide-1.1.1,>idea-1.3.4-SNAPSHOT;<1.2.3
这篇旧文章的另一个解决方案(对那些可能有帮助的人来说):
public class Version implements Comparable<Version> {
private String version;
public final String get() {
return this.version;
}
public Version(String version) {
if(version == null)
throw new IllegalArgumentException("Version can not be null");
if(!version.matches("[0-9]+(\\.[0-9]+)*"))
throw new IllegalArgumentException("Invalid version format");
this.version = version;
}
@Override public int compareTo(Version that) {
if(that == null)
return 1;
String[] thisParts = this.get().split("\\.");
String[] thatParts = that.get().split("\\.");
int length = Math.max(thisParts.length, thatParts.length);
for(int i = 0; i < length; i++) {
int thisPart = i < thisParts.length ?
Integer.parseInt(thisParts[i]) : 0;
int thatPart = i < thatParts.length ?
Integer.parseInt(thatParts[i]) : 0;
if(thisPart < thatPart)
return -1;
if(thisPart > thatPart)
return 1;
}
return 0;
}
@Override public boolean equals(Object that) {
if(this == that)
return true;
if(that == null)
return false;
if(this.getClass() != that.getClass())
return false;
return this.compareTo((Version) that) == 0;
}
}
Version a = new Version("1.1");
Version b = new Version("1.1.1");
a.compareTo(b) // return -1 (a<b)
a.equals(b) // return false
Version a = new Version("2.0");
Version b = new Version("1.9.9");
a.compareTo(b) // return 1 (a>b)
a.equals(b) // return false
Version a = new Version("1.0");
Version b = new Version("1");
a.compareTo(b) // return 0 (a=b)
a.equals(b) // return true
Version a = new Version("1");
Version b = null;
a.compareTo(b) // return 1 (a>b)
a.equals(b) // return false
List<Version> versions = new ArrayList<Version>();
versions.add(new Version("2"));
versions.add(new Version("1.0.5"));
versions.add(new Version("1.01.0"));
versions.add(new Version("1.00.1"));
Collections.min(versions).get() // return min version
Collections.max(versions).get() // return max version
// WARNING
Version a = new Version("2.06");
Version b = new Version("2.060");
a.equals(b) // return false
编辑:
@daiscog:谢谢你的评论,这段代码是为Android平台开发的,由谷歌推荐,方法“匹配”检查整个字符串,不像Java使用监管模式。(Android文档- JAVA文档)
// VersionComparator.java
import java.util.Comparator;
public class VersionComparator implements Comparator {
public boolean equals(Object o1, Object o2) {
return compare(o1, o2) == 0;
}
public int compare(Object o1, Object o2) {
String version1 = (String) o1;
String version2 = (String) o2;
VersionTokenizer tokenizer1 = new VersionTokenizer(version1);
VersionTokenizer tokenizer2 = new VersionTokenizer(version2);
int number1 = 0, number2 = 0;
String suffix1 = "", suffix2 = "";
while (tokenizer1.MoveNext()) {
if (!tokenizer2.MoveNext()) {
do {
number1 = tokenizer1.getNumber();
suffix1 = tokenizer1.getSuffix();
if (number1 != 0 || suffix1.length() != 0) {
// Version one is longer than number two, and non-zero
return 1;
}
}
while (tokenizer1.MoveNext());
// Version one is longer than version two, but zero
return 0;
}
number1 = tokenizer1.getNumber();
suffix1 = tokenizer1.getSuffix();
number2 = tokenizer2.getNumber();
suffix2 = tokenizer2.getSuffix();
if (number1 < number2) {
// Number one is less than number two
return -1;
}
if (number1 > number2) {
// Number one is greater than number two
return 1;
}
boolean empty1 = suffix1.length() == 0;
boolean empty2 = suffix2.length() == 0;
if (empty1 && empty2) continue; // No suffixes
if (empty1) return 1; // First suffix is empty (1.2 > 1.2b)
if (empty2) return -1; // Second suffix is empty (1.2a < 1.2)
// Lexical comparison of suffixes
int result = suffix1.compareTo(suffix2);
if (result != 0) return result;
}
if (tokenizer2.MoveNext()) {
do {
number2 = tokenizer2.getNumber();
suffix2 = tokenizer2.getSuffix();
if (number2 != 0 || suffix2.length() != 0) {
// Version one is longer than version two, and non-zero
return -1;
}
}
while (tokenizer2.MoveNext());
// Version two is longer than version one, but zero
return 0;
}
return 0;
}
}
// VersionTokenizer.java
public class VersionTokenizer {
private final String _versionString;
private final int _length;
private int _position;
private int _number;
private String _suffix;
private boolean _hasValue;
public int getNumber() {
return _number;
}
public String getSuffix() {
return _suffix;
}
public boolean hasValue() {
return _hasValue;
}
public VersionTokenizer(String versionString) {
if (versionString == null)
throw new IllegalArgumentException("versionString is null");
_versionString = versionString;
_length = versionString.length();
}
public boolean MoveNext() {
_number = 0;
_suffix = "";
_hasValue = false;
// No more characters
if (_position >= _length)
return false;
_hasValue = true;
while (_position < _length) {
char c = _versionString.charAt(_position);
if (c < '0' || c > '9') break;
_number = _number * 10 + (c - '0');
_position++;
}
int suffixStart = _position;
while (_position < _length) {
char c = _versionString.charAt(_position);
if (c == '.') break;
_position++;
}
_suffix = _versionString.substring(suffixStart, _position);
if (_position < _length) _position++;
return true;
}
}
例子:
public class Main
{
private static VersionComparator cmp;
public static void main (String[] args)
{
cmp = new VersionComparator();
Test(new String[]{"1.1.2", "1.2", "1.2.0", "1.2.1", "1.12"});
Test(new String[]{"1.3", "1.3a", "1.3b", "1.3-SNAPSHOT"});
}
private static void Test(String[] versions) {
for (int i = 0; i < versions.length; i++) {
for (int j = i; j < versions.length; j++) {
Test(versions[i], versions[j]);
}
}
}
private static void Test(String v1, String v2) {
int result = cmp.compare(v1, v2);
String op = "==";
if (result < 0) op = "<";
if (result > 0) op = ">";
System.out.printf("%s %s %s\n", v1, op, v2);
}
}
输出:
1.1.2 == 1.1.2 ---> same length and value
1.1.2 < 1.2 ---> first number (1) less than second number (2) => -1
1.1.2 < 1.2.0 ---> first number (1) less than second number (2) => -1
1.1.2 < 1.2.1 ---> first number (1) less than second number (2) => -1
1.1.2 < 1.12 ---> first number (1) less than second number (12) => -1
1.2 == 1.2 ---> same length and value
1.2 == 1.2.0 ---> first shorter than second, but zero
1.2 < 1.2.1 ---> first shorter than second, and non-zero
1.2 < 1.12 ---> first number (2) less than second number (12) => -1
1.2.0 == 1.2.0 ---> same length and value
1.2.0 < 1.2.1 ---> first number (0) less than second number (1) => -1
1.2.0 < 1.12 ---> first number (2) less than second number (12) => -1
1.2.1 == 1.2.1 ---> same length and value
1.2.1 < 1.12 ---> first number (2) less than second number (12) => -1
1.12 == 1.12 ---> same length and value
1.3 == 1.3 ---> same length and value
1.3 > 1.3a ---> first suffix ('') is empty, but not second ('a') => 1
1.3 > 1.3b ---> first suffix ('') is empty, but not second ('b') => 1
1.3 > 1.3-SNAPSHOT ---> first suffix ('') is empty, but not second ('-SNAPSHOT') => 1
1.3a == 1.3a ---> same length and value
1.3a < 1.3b ---> first suffix ('a') compared to second suffix ('b') => -1
1.3a < 1.3-SNAPSHOT ---> first suffix ('a') compared to second suffix ('-SNAPSHOT') => -1
1.3b == 1.3b ---> same length and value
1.3b < 1.3-SNAPSHOT ---> first suffix ('b') compared to second suffix ('-SNAPSHOT') => -1
1.3-SNAPSHOT == 1.3-SNAPSHOT ---> same length and value
我写了一个小的Java/Android库来比较版本号:https://github.com/G00fY2/version-compare
它的基本功能是:
public int compareVersions(String versionA, String versionB) {
String[] versionTokensA = versionA.split("\\.");
String[] versionTokensB = versionB.split("\\.");
List<Integer> versionNumbersA = new ArrayList<>();
List<Integer> versionNumbersB = new ArrayList<>();
for (String versionToken : versionTokensA) {
versionNumbersA.add(Integer.parseInt(versionToken));
}
for (String versionToken : versionTokensB) {
versionNumbersB.add(Integer.parseInt(versionToken));
}
final int versionASize = versionNumbersA.size();
final int versionBSize = versionNumbersB.size();
int maxSize = Math.max(versionASize, versionBSize);
for (int i = 0; i < maxSize; i++) {
if ((i < versionASize ? versionNumbersA.get(i) : 0) > (i < versionBSize ? versionNumbersB.get(i) : 0)) {
return 1;
} else if ((i < versionASize ? versionNumbersA.get(i) : 0) < (i < versionBSize ? versionNumbersB.get(i) : 0)) {
return -1;
}
}
return 0;
}
这个代码片段不提供任何错误检查或处理。除此之外,我的库还支持像“1.2-rc”>“1.2-beta”这样的后缀。
此代码尝试解决这种类型的比较版本。
大多数版本说明符,如>= 1.0,都是不言自明的。的 说明符~>具有特殊含义,最好通过示例来说明。~> 2.0.3是 与>= 2.0.3和< 2.1相同。~> 2.1与>= 2.1相同,且< 3.0.
public static boolean apply(String cmpDeviceVersion, String reqDeviceVersion)
{
Boolean equal = !cmpDeviceVersion.contains(">") && !cmpDeviceVersion.contains(">=") &&
!cmpDeviceVersion.contains("<") && !cmpDeviceVersion.contains("<=") &&
!cmpDeviceVersion.contains("~>");
Boolean between = cmpDeviceVersion.contains("~>");
Boolean higher = cmpDeviceVersion.contains(">") && !cmpDeviceVersion.contains(">=") && !cmpDeviceVersion.contains("~>");
Boolean higherOrEqual = cmpDeviceVersion.contains(">=");
Boolean less = cmpDeviceVersion.contains("<") && !cmpDeviceVersion.contains("<=");
Boolean lessOrEqual = cmpDeviceVersion.contains("<=");
cmpDeviceVersion = cmpDeviceVersion.replaceAll("[<>=~]", "");
cmpDeviceVersion = cmpDeviceVersion.trim();
String[] version = cmpDeviceVersion.split("\\.");
String[] reqVersion = reqDeviceVersion.split("\\.");
if(equal)
{
return isEqual(version, reqVersion);
}
else if(between)
{
return isBetween(version, reqVersion);
}
else if(higher)
{
return isHigher(version, reqVersion);
}
else if(higherOrEqual)
{
return isEqual(version, reqVersion) || isHigher(version, reqVersion);
}
else if(less)
{
return isLess(version, reqVersion);
}
else if(lessOrEqual)
{
return isEqual(version, reqVersion) || isLess(version, reqVersion);
}
return false;
}
private static boolean isEqual(String[] version, String[] reqVersion)
{
String strVersion = StringUtils.join(version);
String strReqVersion = StringUtils.join(reqVersion);
if(version.length > reqVersion.length)
{
Integer diff = version.length - reqVersion.length;
strReqVersion += StringUtils.repeat(".0", diff);
}
else if(reqVersion.length > version.length)
{
Integer diff = reqVersion.length - version.length;
strVersion += StringUtils.repeat(".0", diff);
}
return strVersion.equals(strReqVersion);
}
private static boolean isHigher(String[] version, String[] reqVersion)
{
String strVersion = StringUtils.join(version);
String strReqVersion = StringUtils.join(reqVersion);
if(version.length > reqVersion.length)
{
Integer diff = version.length - reqVersion.length;
strReqVersion += StringUtils.repeat(".0", diff);
}
else if(reqVersion.length > version.length)
{
Integer diff = reqVersion.length - version.length;
strVersion += StringUtils.repeat(".0", diff);
}
return strReqVersion.compareTo(strVersion) > 0;
}
private static boolean isLess(String[] version, String[] reqVersion)
{
String strVersion = StringUtils.join(version);
String strReqVersion = StringUtils.join(reqVersion);
if(version.length > reqVersion.length)
{
Integer diff = version.length - reqVersion.length;
strReqVersion += StringUtils.repeat(".0", diff);
}
else if(reqVersion.length > version.length)
{
Integer diff = reqVersion.length - version.length;
strVersion += StringUtils.repeat(".0", diff);
}
return strReqVersion.compareTo(strVersion) < 0;
}
private static boolean isBetween(String[] version, String[] reqVersion)
{
return (isEqual(version, reqVersion) || isHigher(version, reqVersion)) &&
isLess(getNextVersion(version), reqVersion);
}
private static String[] getNextVersion(String[] version)
{
String[] nextVersion = new String[version.length];
for(int i = version.length - 1; i >= 0 ; i--)
{
if(i == version.length - 1)
{
nextVersion[i] = "0";
}
else if((i == version.length - 2) && NumberUtils.isNumber(version[i]))
{
nextVersion[i] = String.valueOf(NumberUtils.toInt(version[i]) + 1);
}
else
{
nextVersion[i] = version[i];
}
}
return nextVersion;
}