Como você compara duas strings de versão em Java?

Existe um idioma padrão para comparar números de versão? Eu não posso simplesmente usar uma string straight compareTo porque eu não sei ainda qual será o número máximo de lançamentos de pontos. Eu preciso comparar as versões e ter o seguinte:

1.0 < 1.1 1.0.1 < 1.1 1.9 < 1.10 

    Tokenize as strings com o ponto como delimitador e compare a tradução inteira lado a lado, começando da esquerda.

    Outra solução para este post antigo (para aqueles que podem ajudar):

     public class Version implements Comparable { 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 (ab) 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 versions = new ArrayList(); 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 

    Editar:

    @daiscog: Obrigado por sua observação, este trecho de código foi desenvolvido para a plataforma Android e, como recomendado pelo Google, o método “matches” verifica toda a string, ao contrário do Java, que usa um padrão de regulamentação. ( Documentação do Android – documentação JAVA )

    É muito fácil usar o Maven:

     import org.apache.maven.artifact.versioning.DefaultArtifactVersion; DefaultArtifactVersion minVersion = new DefaultArtifactVersion("1.0.1"); DefaultArtifactVersion maxVersion = new DefaultArtifactVersion("1.10"); DefaultArtifactVersion version = new DefaultArtifactVersion("1.11"); if (version.compareTo(minVersion) < 0 || version.compareTo(maxVersion) > 0) { System.out.println("Sorry, your version is unsupported"); } 

    Você pode obter a string de dependência correta para o Maven Artifact nesta página :

      org.apache.maven maven-artifact 3.0.3  

    Você precisa normalizar as strings da versão para que possam ser comparadas. Algo como

     import java.util.regex.Pattern; public class Main { public static void main(String... args) { compare("1.0", "1.1"); compare("1.0.1", "1.1"); compare("1.9", "1.10"); compare("1.a", "1.9"); } private static void compare(String v1, String v2) { String s1 = normalisedVersion(v1); String s2 = normalisedVersion(v2); int cmp = s1.compareTo(s2); String cmpStr = cmp < 0 ? "<" : cmp > 0 ? ">" : "=="; System.out.printf("'%s' %s '%s'%n", v1, cmpStr, v2); } public static String normalisedVersion(String version) { return normalisedVersion(version, ".", 4); } public static String normalisedVersion(String version, String sep, int maxWidth) { String[] split = Pattern.compile(sep, Pattern.LITERAL).split(version); StringBuilder sb = new StringBuilder(); for (String s : split) { sb.append(String.format("%" + maxWidth + 's', s)); } return sb.toString(); } } 

    Impressões

     '1.0' < '1.1' '1.0.1' < '1.1' '1.9' < '1.10' '1.a' > '1.9' 

    O melhor para reutilizar o código existente, use a class ComparableVersion do Maven

    vantagens:

    • Licença Apache, versão 2.0,
    • testado
    • usado (copiado) em múltiplos projetos como spring-security-core, jboss etc
    • vários resources
    • já é um java.lang.Comparable
    • basta copiar e colar essa class, nenhuma dependência de terceiros

    Não inclua dependência para o artefato maven, pois isso causará várias dependencies transitivas

     // 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; } } 

    Exemplo:

     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); } } 

    Saída:

     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 

    Imaginando por que todo mundo acha que as versões são feitas apenas de números inteiros – no meu caso não era.

    Por que reinventar a roda (supondo que a versão segue o padrão Semver)

    Primeiro instale https://github.com/vdurmont/semver4j via Maven

    Então use esta biblioteca

     Semver sem = new Semver("1.2.3"); sem.isGreaterThan("1.2.2"); // true 
     public static int compareVersions(String version1, String version2){ String[] levels1 = version1.split("\\."); String[] levels2 = version2.split("\\."); int length = Math.max(levels1.length, levels2.length); for (int i = 0; i < length; i++){ Integer v1 = i < levels1.length ? Integer.parseInt(levels1[i]) : 0; Integer v2 = i < levels2.length ? Integer.parseInt(levels2[i]) : 0; int compare = v1.compareTo(v2); if (compare != 0){ return compare; } } return 0; } 
     public int compare(String v1, String v2) { v1 = v1.replaceAll("\\s", ""); v2 = v2.replaceAll("\\s", ""); String[] a1 = v1.split("\\."); String[] a2 = v2.split("\\."); List l1 = Arrays.asList(a1); List l2 = Arrays.asList(a2); int i=0; while(true){ Double d1 = null; Double d2 = null; try{ d1 = Double.parseDouble(l1.get(i)); }catch(IndexOutOfBoundsException e){ } try{ d2 = Double.parseDouble(l2.get(i)); }catch(IndexOutOfBoundsException e){ } if (d1 != null && d2 != null) { if (d1.doubleValue() > d2.doubleValue()) { return 1; } else if (d1.doubleValue() < d2.doubleValue()) { return -1; } } else if (d2 == null && d1 != null) { if (d1.doubleValue() > 0) { return 1; } } else if (d1 == null && d2 != null) { if (d2.doubleValue() > 0) { return -1; } } else { break; } i++; } return 0; } 

    para meus projetos eu uso minha biblioteca de commons-version https://github.com/raydac/commons-version ela contém duas classs auxiliares – para analisar a versão (a versão analisada pode ser comparada com outro object de versão porque é comparável a uma) e VersionValidator que permite verificar a versão de alguma expressão como !=ide-1.1.1,>idea-1.3.4-SNAPSHOT;<1.2.3

    Eu criei um utilitário simples para comparar versões na plataforma Android usando a convenção de versão semântica . Por isso, funciona apenas para cadeias de caracteres no formato XYZ (Major.Minor.Patch), em que X, Y e Z são números inteiros não negativos. Você pode encontrá-lo no meu GitHub .

    Método Version.compareVersions (String v1, String v2) compara duas strings de versão. Retorna 0 se as versões forem iguais, 1 se a versão v1 for anterior à versão v2, -1 se a versão v1 for posterior à versão v2, -2 se o formato da versão for inválido.

     /** * written by: Stan Towianski - May 2018 * notes: I make assumption each of 3 version sections abc is not longer then 4 digits: aaaa.bbbb.cccc-MODWORD1(-)modnum2 * 5.10.13-release-1 becomes 0000500100013.501 6.0-snapshot becomes 0000600000000.100 * MODWORD1 = -xyz/NotMatching, -SNAPSHOT, -ALPHA, -BETA, -RC, -RELEASE/nothing return: .0, .1, .2, .3, .4, .5 * modnum2 = up to 2 digit/chars second version * */ public class VersionCk { private static boolean isVersionHigher( String baseVersion, String testVersion ) { System.out.println( "versionToComparable( baseVersion ) =" + versionToComparable( baseVersion ) ); System.out.println( "versionToComparable( testVersion ) =" + versionToComparable( testVersion ) + " is this higher ?" ); return versionToComparable( testVersion ).compareTo( versionToComparable( baseVersion ) ) > 0; } //---- not worrying about += for something so small private static String versionToComparable( String version ) { // System.out.println("version - " + version); String versionNum = version; int at = version.indexOf( '-' ); if ( at >= 0 ) versionNum = version.substring( 0, at ); String[] numAr = versionNum.split( "\\." ); String versionFormatted = "0"; for ( String tmp : numAr ) { versionFormatted += String.format( "%4s", tmp ).replace(' ', '0'); } while ( versionFormatted.length() < 12 ) // pad out to aaaa.bbbb.cccc { versionFormatted += "0000"; } // System.out.println( "converted min version =" + versionFormatted + "= : " + versionNum ); return versionFormatted + getVersionModifier( version, at ); } //---- use order low to high: -xyz, -SNAPSHOT, -ALPHA, -BETA, -RC, -RELEASE/nothing returns: 0, 1, 2, 3, 4, 5 private static String getVersionModifier( String version, int at ) { // System.out.println("version - " + version ); String[] wordModsAr = { "-SNAPSHOT", "-ALPHA", "-BETA", "-RC", "-RELEASE" }; if ( at < 0 ) return "." + wordModsAr.length + "00"; // make nothing = RELEASE level int i = 1; for ( String word : wordModsAr ) { if ( ( at = version.toUpperCase().indexOf( word ) ) > 0 ) return "." + i + getSecondVersionModifier( version.substring( at + word.length() ) ); i++; } return ".000"; } //---- add 2 chars for any number after first modifier. -rc2 or -rc-2 returns 02 private static String getSecondVersionModifier( String version ) { System.out.println( "second modifier =" + version + "=" ); Matcher m = Pattern.compile("(.*?)(\\d+).*").matcher( version ); // if ( m.matches() ) // System.out.println( "match ? =" + m.matches() + "= m.group(1) =" + m.group(1) + "= m.group(2) =" + m.group(2) + "= m.group(3) =" + (m.groupCount() >= 3 ? m.group(3) : "x") ); // else // System.out.println( "No match" ); return m.matches() ? String.format( "%2s", m.group(2) ).replace(' ', '0') : "00"; } public static void main(String[] args) { checkVersion( "3.10.0", "3.4.0"); checkVersion( "5.4.2", "5.4.1"); checkVersion( "5.4.4", "5.4.5"); checkVersion( "5.4.9", "5.4.12"); checkVersion( "5.9.222", "5.10.12"); checkVersion( "5.10.12", "5.10.12"); checkVersion( "5.10.13", "5.10.14"); checkVersion( "6.7.0", "6.8"); checkVersion( "6.7", "2.7.0"); checkVersion( "6", "6.3.1"); checkVersion( "4", "4.0.0"); checkVersion( "6.3.0", "6"); checkVersion( "5.10.12-Alpha", "5.10.12-beTA"); checkVersion( "5.10.13-release", "5.10.14-beta"); checkVersion( "6.7.0", "6.8-snapshot"); checkVersion( "6.7.1", "6.7.0-release"); checkVersion( "6-snapshot", "6.0.0-beta"); checkVersion( "6.0-snapshot", "6.0.0-whatthe"); checkVersion( "5.10.12-Alpha-1", "5.10.12-alpha-2"); checkVersion( "5.10.13-release-1", "5.10.13-release2"); checkVersion( "10-rc42", "10.0.0-rc53"); } private static void checkVersion(String baseVersion, String testVersion) { System.out.println( "baseVersion - " + baseVersion ); System.out.println( "testVersion - " + testVersion ); System.out.println( "isVersionHigher = " + isVersionHigher( baseVersion, testVersion ) ); System.out.println( "---------------"); } } 

    alguma saída:

     --------------- baseVersion - 6.7 testVersion - 2.7.0 versionToComparable( baseVersion ) =0000600070000.500 versionToComparable( testVersion ) =0000200070000.500 is this higher ? isVersionHigher = false --------------- baseVersion - 6 testVersion - 6.3.1 versionToComparable( baseVersion ) =0000600000000.500 versionToComparable( testVersion ) =0000600030001.500 is this higher ? isVersionHigher = true --------------- baseVersion - 4 testVersion - 4.0.0 versionToComparable( baseVersion ) =0000400000000.500 versionToComparable( testVersion ) =0000400000000.500 is this higher ? isVersionHigher = false --------------- baseVersion - 6.3.0 testVersion - 6 versionToComparable( baseVersion ) =0000600030000.500 versionToComparable( testVersion ) =0000600000000.500 is this higher ? isVersionHigher = false --------------- baseVersion - 5.10.12-Alpha testVersion - 5.10.12-beTA second modifier == versionToComparable( baseVersion ) =0000500100012.200 second modifier == versionToComparable( testVersion ) =0000500100012.300 is this higher ? second modifier == second modifier == isVersionHigher = true --------------- baseVersion - 5.10.13-release testVersion - 5.10.14-beta second modifier == versionToComparable( baseVersion ) =0000500100013.500 second modifier == versionToComparable( testVersion ) =0000500100014.300 is this higher ? second modifier == second modifier == isVersionHigher = true --------------- baseVersion - 6.7.0 testVersion - 6.8-snapshot versionToComparable( baseVersion ) =0000600070000.500 second modifier == versionToComparable( testVersion ) =0000600080000.100 is this higher ? second modifier == isVersionHigher = true --------------- baseVersion - 6.7.1 testVersion - 6.7.0-release versionToComparable( baseVersion ) =0000600070001.500 second modifier == versionToComparable( testVersion ) =0000600070000.500 is this higher ? second modifier == isVersionHigher = false --------------- baseVersion - 6-snapshot testVersion - 6.0.0-beta second modifier == versionToComparable( baseVersion ) =0000600000000.100 second modifier == versionToComparable( testVersion ) =0000600000000.300 is this higher ? second modifier == second modifier == isVersionHigher = true --------------- baseVersion - 6.0-snapshot testVersion - 6.0.0-whatthe second modifier == versionToComparable( baseVersion ) =0000600000000.100 versionToComparable( testVersion ) =0000600000000.000 is this higher ? second modifier == isVersionHigher = false --------------- baseVersion - 5.10.12-Alpha-1 testVersion - 5.10.12-alpha-2 second modifier =-1= versionToComparable( baseVersion ) =0000500100012.201 second modifier =-2= versionToComparable( testVersion ) =0000500100012.202 is this higher ? second modifier =-2= second modifier =-1= isVersionHigher = true --------------- baseVersion - 5.10.13-release-1 testVersion - 5.10.13-release2 second modifier =-1= versionToComparable( baseVersion ) =0000500100013.501 second modifier =2= versionToComparable( testVersion ) =0000500100013.502 is this higher ? second modifier =2= second modifier =-1= isVersionHigher = true --------------- baseVersion - 10-rc42 testVersion - 10.0.0-rc53 second modifier =42= versionToComparable( baseVersion ) =0001000000000.442 second modifier =53= versionToComparable( testVersion ) =0001000000000.453 is this higher ? second modifier =53= second modifier =42= isVersionHigher = true --------------- 

    Para o Scala, você pode usar uma biblioteca que eu fiz: https://github.com/kypeli/sversion

     Version("1.2") > Version("1.1") // true Version("1.2.1") > Version("1.1.2") // true Version("1.1.1") == Version("1.1.1") // true Version("1.1.1") > Version("1.1") // true Version("1.1.0") == Version("1.1") // true Version("1.1-RC2") > Version("1.1-RC1") // true Version("1.1-RC1") > Version("1.1") // true 

    Escreveu uma pequena function eu mesmo.

      public static boolean checkVersionUpdate(String olderVerison, String newVersion) { if (olderVerison.length() == 0 || newVersion.length() == 0) { return false; } List newVerList = Arrays.asList(newVersion.split("\\.")); List oldVerList = Arrays.asList(olderVerison.split("\\.")); int diff = newVerList.size() - oldVerList.size(); List 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 oldList, List 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; } 

    Deixe-me ser honesto, a comparação lexicográfica da String funcionará muito bem para a maioria do caso.

     "1.0.0".compareTo("1.0.1") // -1 

    Existe algum erro possível, se por exemplo temos alguma formatação em alguma versão

     "1.01.1".compareTo("1.1.0") // -1 should be 1 

    Isso pode ser corrigido facilmente limpando esses valores e, claro, fornecendo alguns methods simples.

     public class Version implements Comparable{ private static final String sanitizeRegex = ".0([1-9]+)"; private String value; public Version(String value){ if(value == null) throw new IllegalArgumentException("A version need a valid value"); this.value = value.replaceAll(sanitizeRegex, ".$1"); } public boolean isLessThan(Version o){ return this.compareTo(o) < 0; } public boolean isGreaterThan(Version o){ return this.compareTo(o) > 0; } public boolean isEquals(Version o) { return this.compareTo(o) == 0; } @Override public int compareTo(Version o) { return this.value.compareTo(o.value); } @Override public String toString() { return value; } } 

    O regex removerá o 0 se necessário.

     01 -> 1 0 -> 0 00 -> 0 10 -> 10 

    Isso nos permite ter uma comparação bem simples usando o que já existe.

    Um rápido teste tirado da resposta de Johan Paul

      System.out.println(new Version("1.2").isGreaterThan(new Version("1.1") )); // true System.out.println(new Version("1.2.1").isGreaterThan(new Version("1.1.2") )); // true System.out.println(new Version("1.1.1").isGreaterThan(new Version("1.1.1") )); // false System.out.println(new Version("1.1.1").isGreaterThan(new Version("1.1") )); // true System.out.println(new Version("1.1.0").isGreaterThan(new Version("1.1") )); // true System.out.println(new Version("1.1-RC2").isGreaterThan(new Version("1.1-RC1"))); // true System.out.println(new Version("1.1-RC1").isGreaterThan(new Version("1.1") )); // true System.out.println(new Version("1.0.1").isGreaterThan(new Version("1.1") )); // false 

    Aqui está uma implementação otimizada:

     public static final Comparator VERSION_ORDER = new Comparator() { @Override public int compare (CharSequence lhs, CharSequence rhs) { int ll = lhs.length(), rl = rhs.length(), lv = 0, rv = 0, li = 0, ri = 0; char c; do { lv = rv = 0; while (--ll >= 0) { c = lhs.charAt(li++); if (c < '0' || c > '9') break; lv = lv*10 + c - '0'; } while (--rl >= 0) { c = rhs.charAt(ri++); if (c < '0' || c > '9') break; rv = rv*10 + c - '0'; } } while (lv == rv && (ll >= 0 || rl >= 0)); return lv - rv; } }; 

    Resultado:

     "0.1" - "1.0" = -1 "1.0" - "1.0" = 0 "1.0" - "1.0.0" = 0 "10" - "1.0" = 9 "3.7.6" - "3.7.11" = -5 "foobar" - "1.0" = -1 

    Este código tenta resolver este tipo de versões de comparação.

    A maioria dos especificadores de versão, como> = 1.0, é autoexplicativa. O especificador ~> tem um significado especial, melhor mostrado pelo exemplo. ~> 2.0.3 é idêntico a> = 2.0.3 e <2.1. ~> 2.1 é idêntico a> = 2.1 e <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; } 

    I liked the idea from @Peter Lawrey, And i extended it to further limits :

      /** * 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= 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); } 

    Espero que ajude alguém. It passed all test cases in interviewbit and leetcode (need to uncomment two lines in compareVersion function).

    Easily tested !

     public class VersionComparator { /* loop through both version strings * then loop through the inner string to computer the val of the int * for each integer read, do num*10+ * and stop when stumbling upon '.' * When '.' is encountered... * see if '.' is encountered for both strings * if it is then compare num1 and num2 * if num1 == num2... iterate over p1++, p2++ * else return (num1 > num2) ? 1 : -1 * If both the string end then compare(num1, num2) return 0, 1, -1 * else loop through the longer string and * verify if it only has trailing zeros * If it only has trailing zeros then return 0 * else it is greater than the other string */ public static int compareVersions(String v1, String v2) { int num1 = 0; int num2 = 0; int p1 = 0; int p2 = 0; while (p1 < v1.length() && p2 < v2.length()) { num1 = Integer.parseInt(v1.charAt(p1) + ""); num2 = Integer.parseInt(v2.charAt(p2) + ""); p1++; p2++; while (p1 < v1.length() && p2 < v2.length() && v1.charAt(p1) != '.' && v2.charAt(p2) != '.') { if (p1 < v1.length()) num1 = num1 * 10 + Integer.parseInt(v1.charAt(p1) + ""); if (p2 < v2.length()) num2 = num2 * 10 + Integer.parseInt(v2.charAt(p2) + ""); p1++; p2++; } if (p1 < v1.length() && p2 < v2.length() && v1.charAt(p1) == '.' && v2.charAt(p2) == '.') { if ((num1 ^ num2) == 0) { p1++; p2++; } else return (num1 > num2) ? 1 : -1; } else if (p1 < v1.length() && p2 < v2.length() && v1.charAt(p1) == '.') return -1; else if (p1 < v1.length() && p2 < v2.length() && v2.charAt(p2) == '.') return 1; } if (p1 == v1.length() && p2 == v2.length()) { if ((num1 ^ num2) == 0) return 0; else return (num1 > num2) ? 1 : -1; } else if (p1 == v1.length()) { if ((num1 ^ num2) == 0) { while (p2 < v2.length()) { if (v2.charAt(p2) != '.' && v2.charAt(p2) != '0') return -1; p2++; } return 0; } else return (num1 > num2) ? 1 : -1; } else { if ((num1 ^ num2) == 0) { while (p1 < v1.length()) { if (v1.charAt(p1) != '.' && v1.charAt(p1) != '0') return 1; p1++; } return 0; } else return (num1 > num2) ? 1 : -1; } } public static void main(String[] args) { System.out.println(compareVersions("11.23", "11.21.1.0.0.1.0") ^ 1); System.out.println(compareVersions("11.21.1.0.0.1.0", "11.23") ^ -1); System.out.println(compareVersions("11.23", "11.23.0.0.0.1.0") ^ -1); System.out.println(compareVersions("11.2", "11.23") ^ -1); System.out.println(compareVersions("11.23", "11.21.1.0.0.1.0") ^ 1); System.out.println(compareVersions("1.21.1.0.0.1.0", "2.23") ^ -1); System.out.println(compareVersions("11.23", "11.21.1.0.0.1.0") ^ 1); System.out.println(compareVersions("11.23.0.0.0.0.0", "11.23") ^ 0); System.out.println(compareVersions("11.23", "11.21.1.0.0.1.0") ^ 1); System.out.println(compareVersions("1.5.1.3", "1.5.1.3.0") ^ 0); System.out.println(compareVersions("1.5.1.4", "1.5.1.3.0") ^ 1); System.out.println(compareVersions("1.2.1.3", "1.5.1.3.0") ^ -1); System.out.println(compareVersions("1.2.1.3", "1.22.1.3.0") ^ -1); System.out.println(compareVersions("1.222.1.3", "1.22.1.3.0") ^ 1); } } 

    My java Solution

      public int compareVersion(String version1, String version2) { String[] first = version1.split("\\."); String[] second = version2.split("\\."); int len = first.length< =second.length? first.length:second.length; // the loop runs for whichever is the short version of two strings for(int i=0;isecondInt){ return 1; } } // below two condition check if the length are the not the same //if first string length is short then start from after first string length and compare it with second string value. second string value is not zero that means it is greater. if(first.lengthsecond.length){ for(int i=second.length;i