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.