python排序自定义版本号

发布时间 2023-03-23 15:05:51作者: lxd670

1.LooseVersion版本排序

格式

# 合法格式
re.compile(r'(\d+ | [a-z]+ | \.)', re.VERBOSE)

成功

from distutils.version import LooseVersion

version_list = ['1.1.2', '1.1.3-rc1', '1.1.2-rc3', '1.1.2-rc1', '1.1.3']
version_list.sort(key=LooseVersion, reverse=True)
print(version_list)
['1.1.3-rc1', '1.1.3', '1.1.2-rc3', '1.1.2-rc1', '1.1.2']

报错

from distutils.version import LooseVersion
version_list = ['1.1.2', '1.1.3-rc1', '1.1.2-rc3', '1.1.2-rc1', '1.1.3', '1.1.2.1']
version_list.sort(key=LooseVersion, reverse=True)
print(version_list)
TypeError: '<' not supported between instances of 'str' and 'int'

2.StrictVersion版本排序

格式

# 合法格式
re.compile(r'^(\d+) \. (\d+) (\. (\d+))? ([ab](\d+))?$',re.VERBOSE | re.ASCII)

成功

from distutils.version import StrictVersion

version_list = ['1.1.2a1','1.1.2a2', '1.1.2b1', '1.1.3', '1.1.1', '1.1.2']
version_list.sort(key=StrictVersion, reverse=True)
print(version_list)
['1.1.3', '1.1.2', '1.1.2b1', '1.1.2a2', '1.1.2a1', '1.1.1']

报错

from distutils.version import StrictVersion

version_list = ['1.1.2', '1.1.3-rc1', '1.1.2-rc3', '1.1.2-rc1', '1.1.3']
version_list.sort(key=StrictVersion, reverse=True)
print(version_list)
ValueError: invalid version number '1.1.3-rc1'

3.自定义MyVersion版本排序

1.1.1.1 > 1.1.1 > 1.1.1-rc1

格式

# 合法格式
re.compile(r'^(\d+)\.(\d+)\.(\d+)((-rc|\.)(\d+))?', re.VERBOSE | re.ASCII)
1.1.1			# 正式版本
1.1.1-rc1		# 预发布版本
1.1.1.1			# 紧急修复版本

自定义排序

from distutils.version import Version

# 复制StrictVersion,并修改
class MyVersion(Version):
  	# 正则获取版本中的数字(更改)
    version_re = re.compile(r'^(\d+)\.(\d+)\.(\d+)((-rc|\.)(\d+))?', re.VERBOSE | re.ASCII)

    def parse(self, vstring):
        match = self.version_re.match(vstring)
        # 重写判断逻辑(更改)
        if match:
            (major, minor, patch, prerelease, prerelease_num) = match.group(1, 2, 3, 5, 6)
            if patch:
                self.version = tuple(map(int, [major, minor, patch]))
            else:
                self.version = tuple(map(int, [major, minor], 0))
            if prerelease == '.':
                self.prerelease = (int(prerelease_num), 10000)
            elif prerelease == '-rc':
                self.prerelease = (0, int(prerelease_num))
            else:
                self.prerelease = (1, 0)
        else:
            self.version = tuple(map(int, [0, 0, 0]))
            self.prerelease = (0, 0)

    # 这个是打印信息时候看的内容(更改)
    def __str__(self):
        return str(self.version + self.prerelease)

    def _cmp(self, other):
        if isinstance(other, str):
          	# 换成自定义的MyVersion(更改)
            other = MyVersion(other)
        if self.version != other.version:
            if self.version < other.version:
                return -1
            else:
                return 1
        if (not self.prerelease and not other.prerelease):
            return 0
        elif (self.prerelease and not other.prerelease):
            return -1
        elif (not self.prerelease and other.prerelease):
            return 1
        elif (self.prerelease and other.prerelease):
            if self.prerelease == other.prerelease:
                return 0
            elif self.prerelease < other.prerelease:
                return -1
            else:
                return 1
        else:
            assert False, "never get here"

测试自定义排序

import re
from myversion import MyVersion

version_list = ['1.1.2', '1.1.3-rc1', '1.1.2-rc3', '1.1.2-rc1', '1.1.3']
version_list.sort(key=MyVersion, reverse=True)
print(version_list)
['1.1.3', '1.1.3-rc1', '1.1.2', '1.1.2-rc3', '1.1.2-rc1']

4.原理

把所有数字提取出来放入元组中比对

根据元组比对

print((1, 0, 1) < (1, 1))			# 1.0.1 < 1.1.0
print((1, 0, 1) < (1, 1, 3))	# 1.0.1 < 1.1.3
print((1, 1, 'a', 1) < (1, 1, 'b', 1))	# 1.1.a.1 < 1.1.b.1
True
True
True

StrictVersion原理

# 设置前3位数字进行大版本号判断
self.version = tuple(map(int, [major, minor, patch]))
# 设置后2两位进行小版本判断
self.prerelease = (prerelease[0], int(prerelease_num))


# 比较【1.1.1a1】和【1.1.1b1】大小
# 版本拆分【1.1.1a1】
version = (1,1,1)
prerelease = ('a',1)

# 版本拆分【1.1.1b1】
version = (1,1,1)
prerelease = ('b',1)

# 先判断大版本号是否相同(可以判断出直接返回)
if self.version != other.version:
    # numeric versions don't match
    # prerelease stuff doesn't matter
    if self.version < other.version:
        return -1
    else:
        return 1
      
# 大版本相同,进行小版本对比
if (not self.prerelease and not other.prerelease):
    return 0
elif (self.prerelease and not other.prerelease):
    return -1
elif (not self.prerelease and other.prerelease):
    return 1
elif (self.prerelease and other.prerelease):
    if self.prerelease == other.prerelease:
        return 0
    elif self.prerelease < other.prerelease:
        return -1
    else:
        return 1
else:
    assert False, "never get here"