Python의 버전 번호 비교


98

내가 쓰고 싶은 cmp두 가지 버전 번호 및 수익률을 비교 -like 기능을 -1, 0또는 1자신의 비교 valuses에 따라.

  • -1버전 A가 버전 B보다 오래된 경우 반환
  • 0버전 A와 B가 동일한 경우 반환
  • 1버전 A가 버전 B보다 새로운 경우 반환

각 하위 섹션은 숫자로 해석되므로 1.10> 1.1입니다.

원하는 기능 출력은 다음과 같습니다.

mycmp('1.0', '1') == 0
mycmp('1.0.0', '1') == 0
mycmp('1', '1.0.0.1') == -1
mycmp('12.10', '11.0.0.0.0') == 1
...

그리고 여기에 내 구현이 있으며 개선을 위해 열려 있습니다.

def mycmp(version1, version2):
    parts1 = [int(x) for x in version1.split('.')]
    parts2 = [int(x) for x in version2.split('.')]

    # fill up the shorter version with zeros ...
    lendiff = len(parts1) - len(parts2)
    if lendiff > 0:
        parts2.extend([0] * lendiff)
    elif lendiff < 0:
        parts1.extend([0] * (-lendiff))

    for i, p in enumerate(parts1):
        ret = cmp(p, parts2[i])
        if ret: return ret
    return 0

Python 2.4.5 btw를 사용하고 있습니다. (내 작업장에 설치 ...).

다음은 사용할 수있는 작은 '테스트 모음'입니다.

assert mycmp('1', '2') == -1
assert mycmp('2', '1') == 1
assert mycmp('1', '1') == 0
assert mycmp('1.0', '1') == 0
assert mycmp('1', '1.000') == 0
assert mycmp('12.01', '12.1') == 0
assert mycmp('13.0.1', '13.00.02') == -1
assert mycmp('1.1.1.1', '1.1.1.1') == 0
assert mycmp('1.1.1.2', '1.1.1.1') == 1
assert mycmp('1.1.3', '1.1.3.000') == 0
assert mycmp('3.1.1.0', '3.1.2.10') == -1
assert mycmp('1.1', '1.10') == -1

대답이 아니라 제안입니다. 버전 번호 비교를 위해 데비안의 알고리즘을 구현하는 것이 좋습니다 (기본적으로 숫자가 아닌 부분과 숫자 부분을 번갈아 정렬). 알고리즘은 여기 에 설명되어 있습니다 ( "문자열은 왼쪽에서 오른쪽으로 비교"에서 시작).
— hobbs

Blargh. 주석에서 지원되는 마크 다운의 하위 집합은 나를 혼동하지 않습니다. 링크는 어리석게 보이지만 어쨌든 작동합니다.
— hobbs

미래의 독자가 사용자 에이전트 버전 구문 분석을 위해 이것을 필요 로하는 경우, 너무 넓은 역사적 변형으로 전용 라이브러리 를 권장합니다 .
— James Broadhead 2012


1
여기에있는 질문은 더 오래되었지만 이 다른 질문 은 표준 질문 으로 기름 부음을받은 것으로 보입니다 . 많은 질문이 그 질문의 중복으로 닫혀 있습니다.
— John Y

답변:


36

문자열에서 흥미롭지 않은 부분 (후행 0과 점)을 제거한 다음 숫자 목록을 비교합니다.

import re

def mycmp(version1, version2):
    def normalize(v):
        return [int(x) for x in re.sub(r'(\.0+)*$','', v).split(".")]
    return cmp(normalize(version1), normalize(version2))

이것은 Pär Wieslander와 동일한 접근 방식이지만 좀 더 간결합니다.

다음은 " Bash에서 점으로 구분 된 버전 형식의 두 문자열을 비교하는 방법? " 덕분에 몇 가지 테스트입니다 .

assert mycmp("1", "1") == 0
assert mycmp("2.1", "2.2") < 0
assert mycmp("3.0.4.10", "3.0.4.2") > 0
assert mycmp("4.08", "4.08.01") < 0
assert mycmp("3.2.1.9.8144", "3.2") > 0
assert mycmp("3.2", "3.2.1.9.8144") < 0
assert mycmp("1.2", "2.1") < 0
assert mycmp("2.1", "1.2") > 0
assert mycmp("5.6.7", "5.6.7") == 0
assert mycmp("1.01.1", "1.1.1") == 0
assert mycmp("1.1.1", "1.01.1") == 0
assert mycmp("1", "1.0") == 0
assert mycmp("1.0", "1") == 0
assert mycmp("1.0", "1.0.1") < 0
assert mycmp("1.0.1", "1.0") > 0
assert mycmp("1.0.2.0", "1.0.2") == 0

2
나는 그것이 작동하지 않을까 봐 걱정된다 rstrip(".0"). "1.0.10"에서 ".10"이 ".1"로 바뀔 것이다.
— RedGlyph 2009

죄송합니다. 함수 : mycmp ( '1.1', '1.10') == 0
— Johannes Charra

정규식을 사용하면 위에서 언급 한 문제가 해결됩니다.
— gnud 2009

이제 다른 사람들의 모든 좋은 아이디어를 솔루션에 통합했습니다. ... :-P 그래도 결국 제가 할 일입니다. 나는이 대답을 받아 들일 것이다. 감사합니다, 여러분
— Johannes Charra

2
참고 cmp ()는 Python 3에서 제거되었습니다. docs.python.org/3.0/whatsnew/3.0.html#ordering-comparisons
— Dominic Cleal 2014 년

279

파이썬을 사용하는 것은 distutils.version.StrictVersion어떻습니까?

>>> from distutils.version import StrictVersion
>>> StrictVersion('10.4.10') > StrictVersion('10.4.9')
True

따라서 귀하의 cmp기능 :

>>> cmp = lambda x, y: StrictVersion(x).__cmp__(y)
>>> cmp("10.4.10", "10.4.11")
-1

더 복잡한 버전 번호를 비교하려는 경우 distutils.version.LooseVersion더 유용하지만 동일한 유형 만 비교해야합니다.

>>> from distutils.version import LooseVersion, StrictVersion
>>> LooseVersion('1.4c3') > LooseVersion('1.3')
True
>>> LooseVersion('1.4c3') > StrictVersion('1.3')  # different types
False

LooseVersion 가장 지능적인 도구가 아니며 쉽게 속일 수 있습니다.

>>> LooseVersion('1.4') > LooseVersion('1.4-rc1')
False

이 품종에서 성공하려면 표준 라이브러리에서 벗어나 setuptools 의 구문 분석 유틸리티를 사용해야 합니다 parse_version.

>>> from pkg_resources import parse_version
>>> parse_version('1.4') > parse_version('1.4-rc2')
True

따라서 특정 사용 사례에 따라 기본 제공 distutils도구가 충분한 지 또는 종속성으로 추가 해야하는지 여부를 결정해야합니다 setuptools.


2
이미 :) 무엇 단지 사용에 가장 적합한 할 것
— 패트릭 울프

2
좋은! 소스를 읽고 이것을 알아 냈습니까? 어디에서나 distutils.version에 대한 문서를 찾을 수 없습니다. :-/
— Adam Spiers

3
문서를 찾을 수 없으면 패키지를 가져 와서 help ()를 사용하십시오.
— rspeed 2011 년

13
하지만 최대 3 개의 숫자 버전 StrictVersion 에서만 작동합니다. 같은 일에 실패합니다 0.4.3.6!
— abergmeier

6
distribute이 답변 의 모든 인스턴스는 패키지와 setuptools함께 번들로 제공되며 그 pkg_resources이후로 ... like, ever . 마찬가지로이 문서pkg_resources.parse_version() 는와 함께 번들로 제공되는 함수에 대한 공식 문서 입니다 setuptools.
— Cecil Curry

30

이 경우 재사용 은 우아함으로 간주됩니까? :)

# pkg_resources is in setuptools
# See http://peak.telecommunity.com/DevCenter/PkgResources#parsing-utilities
def mycmp(a, b):
    from pkg_resources import parse_version as V
    return cmp(V(a),V(b))

7
흠, 어디서 구할 수 있는지 설명하지 않고 표준 라이브러리 외부에서 무언가를 참조하는 것은 그렇게 우아하지 않습니다 . URL을 포함하도록 수정을 제출했습니다. 개인적으로 저는 distutils를 사용하는 것을 선호합니다. 그렇게 간단한 작업을 위해 타사 소프트웨어를 가져 오는 것은 그만한 가치가없는 것 같습니다.
— Adam Spiers 2012

1
@ adam-spiers wut? 해설도 읽었습니까? pkg_resourcesA는 setuptools-bundled 패키지. setuptools모든 Python 설치에서 사실상 필수 이므로 pkg_resources어디에서나 효과적으로 사용할 수 있습니다. 즉, distutils.version하위 패키지도 유용하지만 상위 수준 pkg_resources.parse_version()기능 보다 지능이 훨씬 떨어집니다 . 활용해야 할 것은 버전 문자열에서 기대하는 광기의 정도에 따라 다릅니다.
— Cecil Curry

@CecilCurry 네, 물론 코멘트 (ary)를 읽었습니다. 이것이 제가 그것을 더 좋게 만들기 위해 편집 한 이유입니다. 아마도 당신은 setuptools표준 라이브러리 외부에있는 내 진술에 동의하지 않고 대신 distutils 이 경우에 대한 내가 명시한 선호도에 동의하지 않을 것입니다 . 그렇다면 "효과적 의무"란 정확히 무엇을 의미합니까? 4.5 년 전에 제가이 의견을 썼을 때 "효과적으로 의무적"이었다는 증거를 제공해 주시겠습니까?
— Adam Spiers 2016 년

12

버전 튜플을 반복 할 필요가 없습니다. 목록과 튜플에 내장 된 비교 연산자는 이미 원하는대로 작동합니다. 버전 목록을 해당 길이로 0으로 확장하면됩니다. 파이썬 2.6에서는 izip_longest를 사용하여 시퀀스를 채울 수 있습니다.

from itertools import izip_longest
def version_cmp(v1, v2):
    parts1, parts2 = [map(int, v.split('.')) for v in [v1, v2]]
    parts1, parts2 = zip(*izip_longest(parts1, parts2, fillvalue=0))
    return cmp(parts1, parts2)

낮은 버전에서는 일부지도 해킹이 필요합니다.

def version_cmp(v1, v2):
    parts1, parts2 = [map(int, v.split('.')) for v in [v1, v2]]
    parts1, parts2 = zip(*map(lambda p1,p2: (p1 or 0, p2 or 0), parts1, parts2))
    return cmp(parts1, parts2)

멋지지만 산문과 같은 코드를 읽을 수없는 사람에게는 이해하기 어렵습니다. :) 글쎄, 나는 당신이 가독성을 희생해서 만 솔루션을 단축 할 수 있다고 가정한다 ...
— Johannes Charra

10

이것은 당신의 제안보다 조금 더 간결합니다. 짧은 버전을 0으로 채우는 대신 분할 후 버전 목록에서 후행 0을 제거합니다.

def normalize_version(v):
    parts = [int(x) for x in v.split(".")]
    while parts[-1] == 0:
        parts.pop()
    return parts

def mycmp(v1, v2):
    return cmp(normalize_version(v1), normalize_version(v2))

좋은 사람, thx. 하지만 난 여전히 ... 하나 또는 두 라이너에 대한 바라고 있어요)
— 요하네스 차라

4
+1 @jellybean : 두 줄이 유지 관리 및 가독성에 항상 가장 좋은 것은 아닙니다.이 코드는 매우 명확하고 간결한 코드이며, mycmp필요한 경우 코드에서 다른 용도로 재사용 할 수 있습니다 .
— RedGlyph 2009

@RedGlyph : 당신은 거기에 요점이 있습니다. "읽을 수있는 2 줄"이라고 말 했어야했습니다. :)
— Johannes Charra 2009

안녕하세요 @ Pär Wieslander, Leetcode 문제에서 동일한 문제를 해결하기 위해이 솔루션을 사용할 때 while 루프에서 "list index out of range"라는 오류가 발생합니다. 왜 그런 일이 발생하는지 도와 주시겠습니까? 여기에 문제는 다음과 같습니다 leetcode.com/explore/interview/card/amazon/76/array-and-strings/...
— YouHaveaBigEgo

7

후행 .0및 .00정규식을 제거 하고 배열을 올바르게 비교 split하는 cmp함수를 사용하십시오 .

def mycmp(v1,v2):
 c1=map(int,re.sub('(\.0+)+\Z','',v1).split('.'))
 c2=map(int,re.sub('(\.0+)+\Z','',v2).split('.'))
 return cmp(c1,c2)

물론 긴 줄이 마음에 들면 한 줄로 변환 할 수 있습니다.


2
def compare_version(v1, v2):
    return cmp(*tuple(zip(*map(lambda x, y: (x or 0, y or 0), 
           [int(x) for x in v1.split('.')], [int(y) for y in v2.split('.')]))))

하나의 라이너입니다 (가독성을 위해 분할). 읽을 수 있는지 잘 모르겠습니다 ...


1
예! 그리고 훨씬 더 축소되었습니다 ( tuplebtw는 필요하지 않음) :cmp(*zip(*map(lambda x,y:(x or 0,y or 0), map(int,v1.split('.')), map(int,v2.split('.')) )))
— Paul

2
from distutils.version import StrictVersion
def version_compare(v1, v2, op=None):
    _map = {
        '<': [-1],
        'lt': [-1],
        '<=': [-1, 0],
        'le': [-1, 0],
        '>': [1],
        'gt': [1],
        '>=': [1, 0],
        'ge': [1, 0],
        '==': [0],
        'eq': [0],
        '!=': [-1, 1],
        'ne': [-1, 1],
        '<>': [-1, 1]
    }
    v1 = StrictVersion(v1)
    v2 = StrictVersion(v2)
    result = cmp(v1, v2)
    if op:
        assert op in _map.keys()
        return result in _map[op]
    return result

version_compare"="를 제외하고 php 용으로 구현하십시오 . 모호하기 때문에.


2

목록은 Python에서 비교할 수 있으므로 누군가 숫자를 나타내는 문자열을 정수로 변환하면 기본적인 Python 비교를 성공적으로 사용할 수 있습니다.

cmp함수가 더 이상 존재하지 않는 Python3x를 사용하기 때문에이 접근 방식을 약간 확장해야했습니다 . 나는 모방했다 cmp(a,b)와 함께 (a > b) - (a < b). 그리고 버전 번호는 그다지 깔끔하지 않으며 모든 종류의 영숫자 문자를 포함 할 수 있습니다. 함수가 순서를 알 수 없어 반환되는 경우가 있습니다 False(첫 번째 예 참조).

따라서 질문이 오래되고 이미 답변 된 경우에도 게시하고 있습니다. 누군가의 삶에서 몇 분을 절약 할 수 있기 때문입니다.

import re

def _preprocess(v, separator, ignorecase):
    if ignorecase: v = v.lower()
    return [int(x) if x.isdigit() else [int(y) if y.isdigit() else y for y in re.findall("\d+|[a-zA-Z]+", x)] for x in v.split(separator)]

def compare(a, b, separator = '.', ignorecase = True):
    a = _preprocess(a, separator, ignorecase)
    b = _preprocess(b, separator, ignorecase)
    try:
        return (a > b) - (a < b)
    except:
        return False

print(compare('1.0', 'beta13'))    
print(compare('1.1.2', '1.1.2'))
print(compare('1.2.2', '1.1.2'))
print(compare('1.1.beta1', '1.1.beta2'))

2

외부 종속성을 가져오고 싶지 않은 경우 여기에 Python 3.x 용으로 작성된 시도가 있습니다.

rc, rel(그리고 아마도를 추가 할 수 있음 c) "릴리스 후보"로 간주하고 버전 번호를 두 부분으로 나누고 두 번째 부분의 값이 누락되면 두 번째 부분의 값이 높습니다 (999). 그렇지 않은 문자는 분할을 생성하고 base-36 코드를 통해 하위 번호로 처리됩니다.

import re
from itertools import chain
def compare_version(version1,version2):
    '''compares two version numbers
    >>> compare_version('1', '2') < 0
    True
    >>> compare_version('2', '1') > 0
    True
    >>> compare_version('1', '1') == 0
    True
    >>> compare_version('1.0', '1') == 0
    True
    >>> compare_version('1', '1.000') == 0
    True
    >>> compare_version('12.01', '12.1') == 0
    True
    >>> compare_version('13.0.1', '13.00.02') <0
    True
    >>> compare_version('1.1.1.1', '1.1.1.1') == 0
    True
    >>> compare_version('1.1.1.2', '1.1.1.1') >0
    True
    >>> compare_version('1.1.3', '1.1.3.000') == 0
    True
    >>> compare_version('3.1.1.0', '3.1.2.10') <0
    True
    >>> compare_version('1.1', '1.10') <0
    True
    >>> compare_version('1.1.2','1.1.2') == 0
    True
    >>> compare_version('1.1.2','1.1.1') > 0
    True
    >>> compare_version('1.2','1.1.1') > 0
    True
    >>> compare_version('1.1.1-rc2','1.1.1-rc1') > 0
    True
    >>> compare_version('1.1.1a-rc2','1.1.1a-rc1') > 0
    True
    >>> compare_version('1.1.10-rc1','1.1.1a-rc2') > 0
    True
    >>> compare_version('1.1.1a-rc2','1.1.2-rc1') < 0
    True
    >>> compare_version('1.11','1.10.9') > 0
    True
    >>> compare_version('1.4','1.4-rc1') > 0
    True
    >>> compare_version('1.4c3','1.3') > 0
    True
    >>> compare_version('2.8.7rel.2','2.8.7rel.1') > 0
    True
    >>> compare_version('2.8.7.1rel.2','2.8.7rel.1') > 0
    True

    '''
    chn = lambda x:chain.from_iterable(x)
    def split_chrs(strings,chars):
        for ch in chars:
            strings = chn( [e.split(ch) for e in strings] )
        return strings
    split_digit_char=lambda x:[s for s in re.split(r'([a-zA-Z]+)',x) if len(s)>0]
    splt = lambda x:[split_digit_char(y) for y in split_chrs([x],'.-_')]
    def pad(c1,c2,f='0'):
        while len(c1) > len(c2): c2+=[f]
        while len(c2) > len(c1): c1+=[f]
    def base_code(ints,base):
        res=0
        for i in ints:
            res=base*res+i
        return res
    ABS = lambda lst: [abs(x) for x in lst]
    def cmp(v1,v2):
        c1 = splt(v1)
        c2 = splt(v2)
        pad(c1,c2,['0'])
        for i in range(len(c1)): pad(c1[i],c2[i])
        cc1 = [int(c,36) for c in chn(c1)]
        cc2 = [int(c,36) for c in chn(c2)]
        maxint = max(ABS(cc1+cc2))+1
        return base_code(cc1,maxint) - base_code(cc2,maxint)
    v_main_1, v_sub_1 = version1,'999'
    v_main_2, v_sub_2 = version2,'999'
    try:
        v_main_1, v_sub_1 = tuple(re.split('rel|rc',version1))
    except:
        pass
    try:
        v_main_2, v_sub_2 = tuple(re.split('rel|rc',version2))
    except:
        pass
    cmp_res=[cmp(v_main_1,v_main_2),cmp(v_sub_1,v_sub_2)]
    res = base_code(cmp_res,max(ABS(cmp_res))+1)
    return res


import random
from functools import cmp_to_key
random.shuffle(versions)
versions.sort(key=cmp_to_key(compare_version))

1

가장 읽기 어려운 솔루션이지만 그럼에도 불구하고 한 줄짜리입니다! 반복자를 사용하여 빠르게합니다.

next((c for c in imap(lambda x,y:cmp(int(x or 0),int(y or 0)),
            v1.split('.'),v2.split('.')) if c), 0)

그것은 Python2.6 및 3. + btw, Python 2.5 및 이전 버전은 StopIteration을 포착해야합니다.


1

데비안 패키지 버전 문자열을 구문 분석하고 비교할 수 있도록이 작업을 수행했습니다. 캐릭터 유효성 검사에 엄격하지 않습니다.

이것은 또한 도움이 될 수 있습니다.

#!/usr/bin/env python

# Read <https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version> 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')

0

또 다른 해결책 :

def mycmp(v1, v2):
    import itertools as it
    f = lambda v: list(it.dropwhile(lambda x: x == 0, map(int, v.split('.'))[::-1]))[::-1]
    return cmp(f(v1), f(v2))

다음과 같이 사용할 수도 있습니다.

import itertools as it
f = lambda v: list(it.dropwhile(lambda x: x == 0, map(int, v.split('.'))[::-1]))[::-1]
f(v1) <  f(v2)
f(v1) == f(v2)
f(v1) >  f(v2)

0

내 프로젝트에서 이것을 사용하고 있습니다.

cmp(v1.split("."), v2.split(".")) >= 0

0

몇 년이 지났지 만 여전히이 질문이 맨 위에 있습니다.

다음은 내 버전 정렬 기능입니다. 버전을 숫자와 숫자가 아닌 섹션으로 나눕니다. 숫자는 int나머지 str(목록 항목의 일부) 로 비교됩니다 .

def sort_version_2(data):
    def key(n):
        a = re.split(r'(\d+)', n)
        a[1::2] = map(int, a[1::2])
        return a
    return sorted(data, key=lambda n: key(n))

비교 연산자를 사용하여 함수 key를 일종의 사용자 정의 Version유형 으로 사용할 수 있습니다 . 정말로 사용하고 싶다면 https://stackoverflow.com/a/22490617/9935708cmp 과 같이 할 수 있습니다.

def Version(s):
    s = re.sub(r'(\.0*)*$', '', s)  # to avoid ".0" at end
    a = re.split(r'(\d+)', s)
    a[1::2] = map(int, a[1::2])
    return a

def mycmp(a, b):
    a, b = Version(a), Version(b)
    return (a > b) - (a < b)  # DSM's answer

테스트 스위트가 통과했습니다.


-1

내가 선호하는 솔루션 :

추가 0으로 문자열을 채우고 첫 번째 네 개만 사용하는 것은 이해하기 쉽고 정규식이 필요하지 않으며 람다는 어느 정도 읽기 쉽습니다. 가독성을 위해 두 줄을 사용합니다. 우아함은 짧고 단순합니다.

def mycmp(version1,version2):
  tup = lambda x: [int(y) for y in (x+'.0.0.0.0').split('.')][:4]
  return cmp(tup(version1),tup(version2))

-1

이것은 내 솔루션입니다 (C로 작성, 죄송합니다). 도움이 되셨기를 바랍니다.

int compare_versions(const char *s1, const char *s2) {
    while(*s1 && *s2) {
        if(isdigit(*s1) && isdigit(*s2)) {
            /* compare as two decimal integers */
            int s1_i = strtol(s1, &s1, 10);
            int s2_i = strtol(s2, &s2, 10);

            if(s1_i != s2_i) return s1_i - s2_i;
        } else {
            /* compare as two strings */
            while(*s1 && !isdigit(*s1) && *s2 == *s1) {
                s1++;
                s2++;
            }

            int s1_i = isdigit(*s1) ? 0 : *s1;
            int s2_i = isdigit(*s2) ? 0 : *s2;

            if(s1_i != s2_i) return s1_i - s2_i;
        }
    }

    return 0;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.