是否有比较版本号的标准习语?我不能直接使用String compareTo,因为我还不知道点释放的最大数量是多少。我需要比较版本,并有以下保持正确:

1.0 < 1.1
1.0.1 < 1.1
1.9 < 1.10

当前回答

我喜欢@Peter Lawrey的想法,我把它扩展到更远的范围:

    /**
    * Normalize string array, 
    * Appends zeros if string from the array
    * has length smaller than the maxLen.
    **/
    private String normalize(String[] split, int maxLen){
        StringBuilder sb = new StringBuilder("");
        for(String s : split) {
            for(int i = 0; i<maxLen-s.length(); i++) sb.append('0');
            sb.append(s);
        }
        return sb.toString();
    }

    /**
    * Removes trailing zeros of the form '.00.0...00'
    * (and does not remove zeros from, say, '4.1.100')
    **/
    public String removeTrailingZeros(String s){
        int i = s.length()-1;
        int k = s.length()-1;
        while(i >= 0 && (s.charAt(i) == '.' || s.charAt(i) == '0')){
          if(s.charAt(i) == '.') k = i-1;
          i--;  
        } 
        return s.substring(0,k+1);
    }

    /**
    * Compares two versions(works for alphabets too),
    * Returns 1 if v1 > v2, returns 0 if v1 == v2,
    * and returns -1 if v1 < v2.
    **/
    public int compareVersion(String v1, String v2) {

        // Uncomment below two lines if for you, say, 4.1.0 is equal to 4.1
        // v1 = removeTrailingZeros(v1);
        // v2 = removeTrailingZeros(v2);

        String[] splitv1 = v1.split("\\.");
        String[] splitv2 = v2.split("\\.");
        int maxLen = 0;
        for(String str : splitv1) maxLen = Math.max(maxLen, str.length());
        for(String str : splitv2) maxLen = Math.max(maxLen, str.length());
        int cmp = normalize(splitv1, maxLen).compareTo(normalize(splitv2, maxLen));
        return cmp > 0 ? 1 : (cmp < 0 ? -1 : 0);
    }

希望它能帮助到别人。它通过了interviewbit和leetcode中的所有测试用例(需要取消compareVersion函数中的两行注释)。

很容易测试!

其他回答

科特林:

@kotlin.jvm.Throws(InvalidParameterException::class)
fun String.versionCompare(remoteVersion: String?): Int {
    val remote = remoteVersion?.splitToSequence(".")?.toList() ?: return 1
    val local = this.splitToSequence(".").toList()

    if(local.filter { it.toIntOrNull() != null }.size != local.size) throw InvalidParameterException("version invalid: $this")
    if(remote.filter { it.toIntOrNull() != null }.size != remote.size) throw InvalidParameterException("version invalid: $remoteVersion")

    val totalRange = 0 until kotlin.math.max(local.size, remote.size)
    for (i in totalRange) {
        if (i < remote.size && i < local.size) {
            val result = local[i].compareTo(remote[i])
            if (result != 0) return result
        } else (
            return local.size.compareTo(remote.size)
        )
    }
    return 0
}

我写了一个小的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”这样的后缀。

我喜欢@Peter Lawrey的想法,我把它扩展到更远的范围:

    /**
    * Normalize string array, 
    * Appends zeros if string from the array
    * has length smaller than the maxLen.
    **/
    private String normalize(String[] split, int maxLen){
        StringBuilder sb = new StringBuilder("");
        for(String s : split) {
            for(int i = 0; i<maxLen-s.length(); i++) sb.append('0');
            sb.append(s);
        }
        return sb.toString();
    }

    /**
    * Removes trailing zeros of the form '.00.0...00'
    * (and does not remove zeros from, say, '4.1.100')
    **/
    public String removeTrailingZeros(String s){
        int i = s.length()-1;
        int k = s.length()-1;
        while(i >= 0 && (s.charAt(i) == '.' || s.charAt(i) == '0')){
          if(s.charAt(i) == '.') k = i-1;
          i--;  
        } 
        return s.substring(0,k+1);
    }

    /**
    * Compares two versions(works for alphabets too),
    * Returns 1 if v1 > v2, returns 0 if v1 == v2,
    * and returns -1 if v1 < v2.
    **/
    public int compareVersion(String v1, String v2) {

        // Uncomment below two lines if for you, say, 4.1.0 is equal to 4.1
        // v1 = removeTrailingZeros(v1);
        // v2 = removeTrailingZeros(v2);

        String[] splitv1 = v1.split("\\.");
        String[] splitv2 = v2.split("\\.");
        int maxLen = 0;
        for(String str : splitv1) maxLen = Math.max(maxLen, str.length());
        for(String str : splitv2) maxLen = Math.max(maxLen, str.length());
        int cmp = normalize(splitv1, maxLen).compareTo(normalize(splitv2, maxLen));
        return cmp > 0 ? 1 : (cmp < 0 ? -1 : 0);
    }

希望它能帮助到别人。它通过了interviewbit和leetcode中的所有测试用例(需要取消compareVersion函数中的两行注释)。

很容易测试!

这篇旧文章的另一个解决方案(对那些可能有帮助的人来说):

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文档)

我自己写了一个小函数。更简单地使用列表

 public static boolean checkVersionUpdate(String olderVerison, String newVersion) {
        if (olderVerison.length() == 0 || newVersion.length() == 0) {
            return false;
        }
        List<String> newVerList = Arrays.asList(newVersion.split("\\."));
        List<String> oldVerList = Arrays.asList(olderVerison.split("\\."));

        int diff = newVerList.size() - oldVerList.size();
        List<String> newList = new ArrayList<>();
        if (diff > 0) {
            newList.addAll(oldVerList);
            for (int i = 0; i < diff; i++) {
                newList.add("0");
            }
            return examineArray(newList, newVerList, diff);
        } else if (diff < 0) {
            newList.addAll(newVerList);
            for (int i = 0; i < -diff; i++) {
                newList.add("0");
            }
            return examineArray(oldVerList, newList, diff);
        } else {
            return examineArray(oldVerList, newVerList, diff);
        }

    }

    public static boolean examineArray(List<String> oldList, List<String> newList, int diff) {
        boolean newVersionGreater = false;
        for (int i = 0; i < oldList.size(); i++) {
            if (Integer.parseInt(newList.get(i)) > Integer.parseInt(oldList.get(i))) {
                newVersionGreater = true;
                break;
            } else if (Integer.parseInt(newList.get(i)) < Integer.parseInt(oldList.get(i))) {
                newVersionGreater = false;
                break;
            } else {
                newVersionGreater = diff > 0;
            }
        }

        return newVersionGreater;
    }