File size: 3,405 Bytes
8ede856
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import re


class VersionComparator:
    @staticmethod
    def compare_version(v1: str, v2: str) -> int:
        """根据 Semver 语义版本规范来比较版本号的大小。支持不仅局限于 3 个数字的版本号,并处理预发布标签。

        参考: https://semver.org/lang/zh-CN/

        返回 1 表示 v1 > v2,返回 -1 表示 v1 < v2,返回 0 表示 v1 = v2。
        """
        v1 = v1.lower().replace("v", "")
        v2 = v2.lower().replace("v", "")

        def split_version(version):
            match = re.match(
                r"^([0-9]+(?:\.[0-9]+)*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+(.+))?$",
                version,
            )
            if not match:
                return [], None
            major_minor_patch = match.group(1).split(".")
            prerelease = match.group(2)
            # buildmetadata = match.group(3) # 构建元数据在比较时忽略
            parts = [int(x) for x in major_minor_patch]
            prerelease = VersionComparator._split_prerelease(prerelease)
            return parts, prerelease

        v1_parts, v1_prerelease = split_version(v1)
        v2_parts, v2_prerelease = split_version(v2)

        # 比较数字部分
        length = max(len(v1_parts), len(v2_parts))
        v1_parts.extend([0] * (length - len(v1_parts)))
        v2_parts.extend([0] * (length - len(v2_parts)))

        for i in range(length):
            if v1_parts[i] > v2_parts[i]:
                return 1
            if v1_parts[i] < v2_parts[i]:
                return -1

        # 比较预发布标签
        if v1_prerelease is None and v2_prerelease is not None:
            return 1  # 没有预发布标签的版本高于有预发布标签的版本
        if v1_prerelease is not None and v2_prerelease is None:
            return -1  # 有预发布标签的版本低于没有预发布标签的版本
        if v1_prerelease is not None and v2_prerelease is not None:
            len_pre = max(len(v1_prerelease), len(v2_prerelease))
            for i in range(len_pre):
                p1 = v1_prerelease[i] if i < len(v1_prerelease) else None
                p2 = v2_prerelease[i] if i < len(v2_prerelease) else None

                if p1 is None and p2 is not None:
                    return -1
                if p1 is not None and p2 is None:
                    return 1
                if isinstance(p1, int) and isinstance(p2, str):
                    return -1
                if isinstance(p1, str) and isinstance(p2, int):
                    return 1
                if isinstance(p1, int) and isinstance(p2, int):
                    if p1 > p2:
                        return 1
                    if p1 < p2:
                        return -1
                if isinstance(p1, str) and isinstance(p2, str):
                    if p1 > p2:
                        return 1
                    if p1 < p2:
                        return -1
            return 0  # 预发布标签完全相同

        return 0  # 数字部分和预发布标签都相同

    @staticmethod
    def _split_prerelease(prerelease):
        if not prerelease:
            return None
        parts = prerelease.split(".")
        result = []
        for part in parts:
            if part.isdigit():
                result.append(int(part))
            else:
                result.append(part)
        return result