Version number comparison in Python

后端 未结 17 2062
小蘑菇
小蘑菇 2020-11-27 10:32

I want to write a cmp-like function which compares two version numbers and returns -1, 0, or 1 based on their compared va

17条回答
  •  时光取名叫无心
    2020-11-27 11:38

    I did this in order to be able to parse and compare the Debian package version string. Please notice that it is not strict with the character validation.

    This might be helpful as well:

    #!/usr/bin/env python
    
    # Read  for further informations.
    
    class CommonVersion(object):
        def __init__(self, version_string):
            self.version_string = version_string
            self.tags = []
            self.parse()
    
        def parse(self):
            parts = self.version_string.split('~')
            self.version_string = parts[0]
            if len(parts) > 1:
                self.tags = parts[1:]
    
    
        def __lt__(self, other):
            if self.version_string < other.version_string:
                return True
            for index, tag in enumerate(self.tags):
                if index not in other.tags:
                    return True
                if self.tags[index] < other.tags[index]:
                    return True
    
        @staticmethod
        def create(version_string):
            return UpstreamVersion(version_string)
    
    class UpstreamVersion(CommonVersion):
        pass
    
    class DebianMaintainerVersion(CommonVersion):
        pass
    
    class CompoundDebianVersion(object):
        def __init__(self, epoch, upstream_version, debian_version):
            self.epoch = epoch
            self.upstream_version = UpstreamVersion.create(upstream_version)
            self.debian_version = DebianMaintainerVersion.create(debian_version)
    
        @staticmethod
        def create(version_string):
            version_string = version_string.strip()
            epoch = 0
            upstream_version = None
            debian_version = '0'
    
            epoch_check = version_string.split(':')
            if epoch_check[0].isdigit():
                epoch = int(epoch_check[0])
                version_string = ':'.join(epoch_check[1:])
            debian_version_check = version_string.split('-')
            if len(debian_version_check) > 1:
                debian_version = debian_version_check[-1]
                version_string = '-'.join(debian_version_check[0:-1])
    
            upstream_version = version_string
    
            return CompoundDebianVersion(epoch, upstream_version, debian_version)
    
        def __repr__(self):
            return '{} {}'.format(self.__class__.__name__, vars(self))
    
        def __lt__(self, other):
            if self.epoch < other.epoch:
                return True
            if self.upstream_version < other.upstream_version:
                return True
            if self.debian_version < other.debian_version:
                return True
            return False
    
    
    if __name__ == '__main__':
        def lt(a, b):
            assert(CompoundDebianVersion.create(a) < CompoundDebianVersion.create(b))
    
        # test epoch
        lt('1:44.5.6', '2:44.5.6')
        lt('1:44.5.6', '1:44.5.7')
        lt('1:44.5.6', '1:44.5.7')
        lt('1:44.5.6', '2:44.5.6')
        lt('  44.5.6', '1:44.5.6')
    
        # test upstream version (plus tags)
        lt('1.2.3~rc7',          '1.2.3')
        lt('1.2.3~rc1',          '1.2.3~rc2')
        lt('1.2.3~rc1~nightly1', '1.2.3~rc1')
        lt('1.2.3~rc1~nightly2', '1.2.3~rc1')
        lt('1.2.3~rc1~nightly1', '1.2.3~rc1~nightly2')
        lt('1.2.3~rc1~nightly1', '1.2.3~rc2~nightly1')
    
        # test debian maintainer version
        lt('44.5.6-lts1', '44.5.6-lts12')
        lt('44.5.6-lts1', '44.5.7-lts1')
        lt('44.5.6-lts1', '44.5.7-lts2')
        lt('44.5.6-lts1', '44.5.6-lts2')
        lt('44.5.6-lts1', '44.5.6-lts2')
        lt('44.5.6',      '44.5.6-lts1')
    

提交回复
热议问题