比较版本号字符串(主要,次要,修订版,测试版)

我有一个与设备固件通信的应用程序。 由于固件有变化,因此版本的格式为{major}.{minor}.{revision}[beta[{beta}]] 。 举几个例子,目前的版本是0.4.7beta ,接着是0.4.7beta2 ,偶尔是0.4.7 ,然后是0.4.8beta 。 遗憾的是,固件的版本控制格式不在我的控制之下,因此我无法对其进行更改。

我需要一种相互比较固件的方法。 基本上,我需要一个function

 boolean isFirmwareNewer(String testFW, String baseFW); 

到目前为止我所做的是将这种格式转换为简单的int 。 因此0.4.7beta2将成为00040702 (每个级别2位数)。 问题是,那

  1. 我的代码难以阅读(> 40行和3种方法)
  2. 我相信,有一个优雅的解决方案(也许使用正则表达式?)
  3. 我希望有一个通配符0.0.0 ,它更新
  4. 这样处理beta版本不正确( 0.4.7beta2不比0.4.7更新)。 这很容易解释( if (testFW.contains("beta")) testFWValue -= 100;但它也不是很优雅。

你们是如何做到这一点的(或者你会怎么做)?

如果你愿意,我可以附上我目前正在使用的代码,但正如我所说,它是> 40行代码而不是真正可读(这就是我寻找更好的方法来实现这一目的的原因)。

这是一个建议:

 static int[] getVersionNumbers(String ver) { Matcher m = Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)(beta(\\d*))?") .matcher(ver); if (!m.matches()) throw new IllegalArgumentException("Malformed FW version"); return new int[] { Integer.parseInt(m.group(1)), // major Integer.parseInt(m.group(2)), // minor Integer.parseInt(m.group(3)), // rev. m.group(4) == null ? Integer.MAX_VALUE // no beta suffix : m.group(5).isEmpty() ? 1 // "beta" : Integer.parseInt(m.group(5)) // "beta3" }; } static boolean isFirmwareNewer(String testFW, String baseFW) { int[] testVer = getVersionNumbers(testFW); int[] baseVer = getVersionNumbers(baseFW); for (int i = 0; i < testVer.length; i++) if (testVer[i] != baseVer[i]) return testVer[i] > baseVer[i]; return true; } 

它使用一个小技巧并将beta部分翻译如下:

  • "" (没有beta后缀)→Beta MAX_INT
  • "beta" →Beta 1(因为它在“beta2”之前)
  • "betaX" →Beta X.

请注意,如果两个版本相同,则返回true

我会实现一个类似的类:

 class Version implements Comparable { int major; int minor; int rev; int beta = Integer.MAX_VALUE; public int compareTo(Version o) { if (this.major != o.major) { return Integer.compare(this.major, o.major); } if (this.minor != o.minor) { return Integer.compare(this.minor, o.minor); } if (this.rev != o.rev) { return Integer.compare(this.rev, o.rev); } if (this.beta != o.beta) { return Integer.compare(this.beta, o.beta); } return 0; } public static Version parse(String version) { // TODO: implement parsing here // 1.1.1 - beta = MAX_VALUE // 1.1.1beta - beta = 1 // 1.1.1beta2 - beta = 2 return new Version(); } @Override public String toString() { return "" + major + "." + minor + "." + rev + (beta == Integer.MAX_VALUE ? "" : (beta == 1 ? "beta" : ("beta" + beta))); } } 

然后以标准的java方式进行比较:

 if (Version.parse(testFW).compareTo(Version.parse(baseFW)) < 0) { // Version is newer! } 

对于我的项目,我通过遵循语义版本2.0.0使用了这种方法:

 private static String[] formatVersionString(String[] strArr){ //remove trailing 0s List list = new ArrayList<>(); boolean foundChar = false; for(int i=strArr.length-1;i>=0;i--){ String curChar = strArr[i]; if(curChar.equals("0") && !foundChar){ continue; } else{ list.add(strArr[i]); foundChar = true; } } Collections.reverse(list); return list.toArray(new String[list.size()]); } private static String getPreReleaseBuildStr(String buildStr){ //removing build metadata if(buildStr == null){ return null; } String [] a = buildStr.split("\\+"); if(a.length>0){ return a[0]; } else{ return null; } } private static int compareVersionString(String str1,String str2){ int ret = 0; String[] verStr1 = formatVersionString(str1.split("\\.")); String[] verStr2 = formatVersionString(str2.split("\\.")); int i = 0; // set index to first non-equal ordinal or length of shortest version string while (i < verStr1.length && i < verStr2.length && verStr1[i].equals(verStr2[i])) { i++; } // compare first non-equal ordinal number if (i < verStr1.length && i < verStr2.length) { int diff = 0; try{ if(verStr1[i] == null || verStr1[i].trim().length() == 0) { verStr1[i] = "0"; } if(verStr2[i] == null || verStr2[i].trim().length() == 0) { verStr2[i] = "0"; } diff = Integer.valueOf(verStr1[i]).compareTo(Integer.valueOf(verStr2[i])); }catch(NumberFormatException e){ diff = verStr1[i].compareTo(verStr2[i]); } finally{ ret = Integer.signum(diff); } } else{ // the strings are equal or one string is a substring of the other // eg "1.2.3" = "1.2.3" or "1.2.3" < "1.2.3.4" ret = Integer.signum(verStr1.length - verStr2.length); } return ret; } /** * Compares two version strings. * follow this link for more info http://semver.org/ * * Use this instead of String.compareTo() for a non-lexicographical * comparison that works for version strings. eg "1.10".compareTo("1.6"). * * Ex:-- * //1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0 < 2.0.0.6 * * @param str1 a string of ordinal numbers separated by decimal points. * @param str2 a string of ordinal numbers separated by decimal points. * @return The result is a negative integer if str1 is _numerically_ less than str2. * The result is a positive integer if str1 is _numerically_ greater than str2. * The result is zero if the strings are _numerically_ equal. */ public static int versionCompare(String str1, String str2) { int ret = 0; String[] val1 = str1.split("-"); String[] val2 = str2.split("-"); String preReleaseVer1 = null, preReleaseVer2 = null; if(val1.length>1){ preReleaseVer1 = getPreReleaseBuildStr(val1[1]); } if(val2.length>1){ preReleaseVer2 = getPreReleaseBuildStr(val2[1]); } ret = compareVersionString(val1[0],val2[0]); if(ret == 0){ //if both version are equal then compare with pre_release String if(preReleaseVer1 == null && preReleaseVer2 == null){ ret = 0; } else if(preReleaseVer1 == null && preReleaseVer2!=null){ //1.0.0 > 1.0.0-beta ret = 1; } else if(preReleaseVer1 != null && preReleaseVer2==null){ //1.0.0-beta < 1.0.0 ret = -1; } else{ //both hasve pre release string ret = compareVersionString(preReleaseVer1,preReleaseVer2); } } return ret; } 

使用versionCompare(String str1,String str2)方法进行任何比较

代码示例:---

 public class Main { public static void main (String[] args) { //1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0 Test(new String[]{"1.0.0-alpha","1.0.0-alpha.1","1.0.0-alpha.beta","1.0.0-beta", "1.0.0-beta.2","1.0.0-beta.11","1.0.0-rc.1","1.0.0","2.0.0.1"}); } private static void Test(String[] versions) { for (int i = 0; i < versions.length; i++) { for (int j = 0; j < versions.length; j++) { Test(versions[i], versions[j]); } } } private static void Test(String v1, String v2) { int result = versionCompare(v1,v2); String op = "=="; if (result < 0) op = "<"; if (result > 0) op = ">"; System.out.printf("%s %s %s\n", v1, op, v2); } } 

上面例子的输出如下:---

 1.0.0-alpha == 1.0.0-alpha 1.0.0-alpha < 1.0.0-alpha.1 1.0.0-alpha < 1.0.0-alpha.beta 1.0.0-alpha < 1.0.0-beta 1.0.0-alpha < 1.0.0-beta.2 1.0.0-alpha < 1.0.0-beta.11 1.0.0-alpha < 1.0.0-rc.1 1.0.0-alpha < 1.0.0 1.0.0-alpha < 2.0.0.1 1.0.0-alpha.1 > 1.0.0-alpha 1.0.0-alpha.1 == 1.0.0-alpha.1 1.0.0-alpha.1 < 1.0.0-alpha.beta 1.0.0-alpha.1 < 1.0.0-beta 1.0.0-alpha.1 < 1.0.0-beta.2 1.0.0-alpha.1 < 1.0.0-beta.11 1.0.0-alpha.1 < 1.0.0-rc.1 1.0.0-alpha.1 < 1.0.0 1.0.0-alpha.1 < 2.0.0.1 1.0.0-alpha.beta > 1.0.0-alpha 1.0.0-alpha.beta > 1.0.0-alpha.1 1.0.0-alpha.beta == 1.0.0-alpha.beta 1.0.0-alpha.beta < 1.0.0-beta 1.0.0-alpha.beta < 1.0.0-beta.2 1.0.0-alpha.beta < 1.0.0-beta.11 1.0.0-alpha.beta < 1.0.0-rc.1 1.0.0-alpha.beta < 1.0.0 1.0.0-alpha.beta < 2.0.0.1 1.0.0-beta > 1.0.0-alpha 1.0.0-beta > 1.0.0-alpha.1 1.0.0-beta > 1.0.0-alpha.beta 1.0.0-beta == 1.0.0-beta 1.0.0-beta < 1.0.0-beta.2 1.0.0-beta < 1.0.0-beta.11 1.0.0-beta < 1.0.0-rc.1 1.0.0-beta < 1.0.0 1.0.0-beta < 2.0.0.1 1.0.0-beta.2 > 1.0.0-alpha 1.0.0-beta.2 > 1.0.0-alpha.1 1.0.0-beta.2 > 1.0.0-alpha.beta 1.0.0-beta.2 > 1.0.0-beta 1.0.0-beta.2 == 1.0.0-beta.2 1.0.0-beta.2 < 1.0.0-beta.11 1.0.0-beta.2 < 1.0.0-rc.1 1.0.0-beta.2 < 1.0.0 1.0.0-beta.2 < 2.0.0.1 1.0.0-beta.11 > 1.0.0-alpha 1.0.0-beta.11 > 1.0.0-alpha.1 1.0.0-beta.11 > 1.0.0-alpha.beta 1.0.0-beta.11 > 1.0.0-beta 1.0.0-beta.11 > 1.0.0-beta.2 1.0.0-beta.11 == 1.0.0-beta.11 1.0.0-beta.11 < 1.0.0-rc.1 1.0.0-beta.11 < 1.0.0 1.0.0-beta.11 < 2.0.0.1 1.0.0-rc.1 > 1.0.0-alpha 1.0.0-rc.1 > 1.0.0-alpha.1 1.0.0-rc.1 > 1.0.0-alpha.beta 1.0.0-rc.1 > 1.0.0-beta 1.0.0-rc.1 > 1.0.0-beta.2 1.0.0-rc.1 > 1.0.0-beta.11 1.0.0-rc.1 == 1.0.0-rc.1 1.0.0-rc.1 < 1.0.0 1.0.0-rc.1 < 2.0.0.1 1.0.0 > 1.0.0-alpha 1.0.0 > 1.0.0-alpha.1 1.0.0 > 1.0.0-alpha.beta 1.0.0 > 1.0.0-beta 1.0.0 > 1.0.0-beta.2 1.0.0 > 1.0.0-beta.11 1.0.0 > 1.0.0-rc.1 1.0.0 == 1.0.0 1.0.0 < 2.0.0.1 2.0.0.1 > 1.0.0-alpha 2.0.0.1 > 1.0.0-alpha.1 2.0.0.1 > 1.0.0-alpha.beta 2.0.0.1 > 1.0.0-beta 2.0.0.1 > 1.0.0-beta.2 2.0.0.1 > 1.0.0-beta.11 2.0.0.1 > 1.0.0-rc.1 2.0.0.1 > 1.0.0 2.0.0.1 == 2.0.0.1 3.5.6-beta == 3.5.6-beta 3.5.6-beta == 3.5.6-beta.0 3.5.6-beta.0 == 3.5.6-beta 3.5.6-beta.0 == 3.5.6-beta.0