views:

2356

answers:

8

Is there a standard idiom for comparing version numbers? I can't just use a straight String compareTo because I don't know yet what the maximum number of point releases there will be. I need to compare the versions and have the following hold true:

1.0 < 1.1
1.0.1 < 1.1
1.9 < 1.10
A: 

Perhaps have a look at Maven, they have a mechanism. Perhaps you can reuse some of the utility classes...

Hans Doggen
+8  A: 

Tokenize the strings with the dot as delimiter and then compare the integer translation side by side, begining from the left.

gizmo
This is what I suspected I'd have to resort to. This also involves looping over the tokens in the shorter of the two version strings. Thanks for confirming.
Bill the Lizard
and don't forget you might not always have only numbers. some apps will include build numbers, and might include things like 1.0.1b for beta/etc.
John Gardner
A: 

Are the versions always constant? I mean, do the versions always follow a major.minor.release numerical pattern? If so, you can tokenize them and just compare the resulting values.

If you are unsure of the version number pattern or even of the fact that the version number is growing with every new release, that sounds like a psychic ability.

Regards

Bogdan
I don't know how many points the version number will have. So, from 1.0 we could go to 1.0.1, then to 1.1, then to 1.2, and so on.
Bill the Lizard
I think version number under discussion are from CVS. They do have a well-defined pattern but are not fixed size. Complexity is due to the fact that the number also contains branch number.
Tahir Akhtar
I actually made those up. I'm really working with the version numbers from several different communications standards. At the moment I only know two of N that I need to support, so I was hoping for a flexible solution.
Bill the Lizard
A: 

I think you can say that Most Significant Part of the version number is on the left. In that case the algorithm suggested by Gizmo will work. Just break the loop on the first mis-match (not equals) and decide the result based on that comparison. If you run out of one string (with all parts so far being equal) the longer string represents the latest version.

Tahir Akhtar
A: 

simple program

String b = "1.0.1";
String a = "1.2.3";
String a2 = a.replaceAll("\\.", "");
String b2 = b.replaceAll("\\.", "");

System.out.println(a2);
System.out.println(b2);
System.out.println(Integer.valueOf(a2) < Integer.valueOf(b2));
anjanb
That won't work when comparing version 1.0.1 to version 1.1
Bill the Lizard
A: 

As Hans Doggen points out above, Maven does have code that addresses this problem. Specifically, have a look at the ArtifactVersion interface and the DefaultArtifactVersion implementation.

ArtifactVersion implements Comparable, so you can use the compareTo() method to determine whether a version is greater or less than another. On the whole there's not a lot of code in that package; I suspect that this could be lifted out pretty easily, assuming you can incorporate Apache-licensed code in your project (and indeed, Apache has a relatively non-restrictive open-source license).

Hans L
+2  A: 

You need to normalise the version strings so they can be compared. Something like

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

Prints

'1.0' < '1.1'
'1.0.1' < '1.1'
'1.9' < '1.10'
'1.a' > '1.9'
Peter Lawrey
A: 
public int compare(String v1, String v2) {
        v1 = v1.replaceAll("\\s", "");
        v2 = v2.replaceAll("\\s", "");
        String[] a1 = v1.split("\\.");
        String[] a2 = v2.split("\\.");
        List<String> l1 = Arrays.asList(a1);
        List<String> 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;
    }
Cenk Alti