IT Consultant – Java, J2EE, IBM WebSphere Portal, Lotus Notes/Domino
RSS icon Home icon
  • Comparing version numbers in Jython / Python

    1 Star2 Stars3 Stars4 Stars5 Stars
    Loading...Loading...
    Posted on 14 March 2009 No comments

    Here comes a function to compare version numbers of e.g. Maven artifacts in Jython / Python.

    import re
    
    def cmpver(vA, vB):
        """
        Compares two version number strings
        @param vA: first version string to compare
        @param vB: second version string to compare
        @author Sebastian Thomschke
        @return negative if vA < vB, zero if vA == vB, positive if vA > vB.
       
        Examples:
        >>> cmpver("0", "1")
        -1
        >>> cmpver("1", "0")
        1
        >>> cmpver("1", "1")
        0
        >>> cmpver("1.0", "1.0")
        0
        >>> cmpver("1.0", "1")
        0
        >>> cmpver("1", "1.0")
        0
        >>> cmpver("1.1.0", "1.0.1")
        1
        >>> cmpver("1.0.1", "1.1.1")
        -1
        >>> cmpver("0.3-SNAPSHOT", "0.3")
        -1
        >>> cmpver("0.3", "0.3-SNAPSHOT")
        1
        >>> cmpver("1.3b", "1.3c")
        -1
        >>> cmpver("1.14b", "1.3c")
        1
        """
        if vA == vB: return 0
    
        def num(s): 
            if s.isdigit(): return int(s)
            return s
    
        seqA = map(num, re.findall('\d+|\w+', vA.replace('-SNAPSHOT', '')))
        seqB = map(num, re.findall('\d+|\w+', vB.replace('-SNAPSHOT', '')))
    
        # this is to ensure that 1.0 == 1.0.0 in cmp(..)
        lenA, lenB = len(seqA), len(seqB)
        for i in range(lenA, lenB): seqA += (0,) 
        for i in range(lenB, lenA): seqB += (0,)
        
        rc = cmp(seqA, seqB)
        
        if rc == 0:
            if vA.endswith('-SNAPSHOT'): return -1
            if vB.endswith('-SNAPSHOT'): return 1
        return rc
    

    Theoretically lines 43 – 49 could be written in a more compact way but using the short circuit evaluations (as below) lead to wrong results – at least in Jython 2.1:

        seqa = map(lambda s: s.isdigit() and int(s) or s, re.findall('\d+|\w+', vA.replace('-SNAPSHOT', '')))
        seqb = map(lambda s: s.isdigit() and int(s) or s, re.findall('\d+|\w+', vB.replace('-SNAPSHOT', '')))
    

    Leave a reply