Python'da sürüm numarası karşılaştırması


98

Ben yazmak istiyorum cmpiki sürüm numaraları ve getiri karşılaştırır benzeri işlevi -1, 0ya 1da karşılaştırıldı valuses dayalı.

  • -1A sürümü, B sürümünden daha eskiyse dön
  • 0A ve B sürümleri eşdeğerse dön
  • 1A sürümü, B sürümünden daha yeniyse dön

Her bir alt bölümün bir sayı olarak yorumlanması gerekiyor, bu nedenle 1.10> 1.1.

İstenilen fonksiyon çıktıları

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
...

Ve işte geliştirmeye açık uygulamam:

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 kullanıyorum. (çalışma yerimde kurulu ...).

İşte kullanabileceğiniz küçük bir 'test paketi'

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

Bir cevap değil, bir öneri - Debian'ın sürüm numarası karşılaştırması için algoritmasını uygulamaya değer olabilir (temelde sayısal olmayan ve sayısal kısımların dönüşümlü olarak sıralanması). Algoritma burada açıklanmıştır ("Dizeler soldan sağa karşılaştırılır" bölümünden başlayarak).
hobbs

Blargh. Yorumlarda desteklenen markdown alt kümesi beni asla şaşırtmaz. Aptal görünse bile bağlantı yine de çalışıyor.
hobbs

Gelecekteki okuyucuların kullanıcı aracısı sürüm ayrıştırması için buna ihtiyaç duyması halinde, tarihsel varyasyon çok geniş olduğu için özel bir kitaplık öneririm .
James Broadhead


1
Buradaki soru daha eski olsa da, görünen o ki bu diğer soru , kanonik soru olarak işaretlenmiş, çünkü pek çok soru, bu sorunun kopyaları olarak kapatılmış durumda.
John Y

Yanıtlar:


37

Dizenin ilginç olmayan kısmını (sondaki sıfırlar ve noktalar) kaldırın ve ardından sayı listelerini karşılaştırın.

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))

Bu, Pär Wieslander ile aynı yaklaşım, ancak biraz daha kompakt:

" Bash'de noktayla ayrılmış sürüm biçiminde iki dizge nasıl karşılaştırılır? " Sayesinde bazı testler şunlardır :

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
Korkarım işe yaramayacak, rstrip(".0")"1.0.10" da ".10" ".1" olarak değişecek.
RedGlyph

Maalesef, işlevinizle: mycmp ('1.1', '1.10') == 0
Johannes Charra

Normal ifade kullanımıyla, yukarıda bahsedilen sorun çözüldü.
gnud

Şimdi diğerlerinden gelen tüm iyi fikirleri çözümünüzde birleştirdiniz ...: -P Yine de, sonuçta yapacağım şey bu. Bu cevabı kabul edeceğim. Herkese teşekkürler
Johannes Charra

2
Not cmp () Python 3'te kaldırılmıştır: docs.python.org/3.0/whatsnew/3.0.html#ordering-comparisons
Dominic Cleal,

279

Python'u kullanmaya ne dersiniz distutils.version.StrictVersion?

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

Yani cmpişleviniz için:

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

Daha karmaşık olan sürüm numaralarını karşılaştırmak isterseniz distutils.version.LooseVersiondaha kullanışlı olacaktır, ancak yalnızca aynı türleri karşılaştırdığınızdan emin olun.

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

LooseVersion en akıllı araç değildir ve kolayca kandırılabilir:

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

Bu türle başarılı olmak için, standart kitaplığın dışına çıkmanız ve setuptools'un ayrıştırma yardımcı programını kullanmanız gerekir parse_version.

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

Bu nedenle, özel kullanım durumunuza bağlı olarak, yerleşik distutilsaraçların yeterli olup olmadığına veya bir bağımlılık olarak eklenmesinin garanti edilip edilmediğine karar vermeniz gerekir setuptools.


2
zaten orada olanı kullanmak en mantıklı gibi görünüyor :)
Patrick Wolf

2
Güzel! Bunu kaynağı okuyarak mı anladınız? Hiçbir yerde distutils.version için doküman bulamıyorum: - /
Adam

3
Belgeleri bulamadığınız her an paketi içe aktarmayı deneyin ve yardım () kullanın.
rspeed

13
Yine de, StrictVersion YALNIZCA üç sayıya kadar sürümle çalıştığını unutmayın. Böyle şeyler için başarısız oluyor 0.4.3.6!
abergmeier

6
Her örneği distributebu cevap değiştirilmesi gerektiğini setuptoolsile birlikte geliyor, hangi pkg_resources, paket ve benzeri ... zamandan beri hiç . Aynı şekilde, bu, birlikte verilen işlev için resmi belgelerdir . pkg_resources.parse_version()setuptools
Cecil Curry

30

Is yeniden bu durumda zarafeti kabul? :)

# 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
Hmm, nereden alacağınızı açıklamadan standart kitaplığın dışındaki bir şeye atıfta bulunduğunuzda o kadar zarif değil. URL'yi eklemek için bir düzenleme gönderdim. Şahsen ben dağıtımları kullanmayı tercih ederim - bu kadar basit bir görev için 3. taraf yazılımları kullanmaya değmez gibi görünüyor.
Adam Spiers

1
@ adam-spiers wut? Yorumu bile okudun mu? pkg_resourcesBir olan setuptools-bundled paketi. Yana setuptoolstüm Python kurulumlarında etkili bir zorunludur, pkg_resourcesher yerde etkin bir şekilde kullanılabilir. Bununla birlikte, distutils.versionalt paket de kullanışlıdır - üst düzey pkg_resources.parse_version()işlevden önemli ölçüde daha az akıllıdır . Hangisinden yararlanmanız gerektiği, sürüm dizilerinde ne kadar çılgınlık beklediğinize bağlıdır.
Cecil Curry

@CecilCurry Evet tabi ki yorumu (ary) okudum, bu yüzden onu daha iyi hale getirmek için düzenledim ve sonra sahip olduğumu belirttim. Muhtemelen setuptoolsstandart kitaplığın dışındaki ifademe ve bunun yerine distutils bu durumda belirttiğim tercihe katılmıyorsunuz . Öyleyse, "fiilen zorunlu" derken tam olarak neyi kastediyorsunuz ve lütfen 4,5 yıl önce bu yorumu yazdığım zaman bunun "etkili bir şekilde zorunlu" olduğuna dair kanıt sağlayabilir misiniz?
Adam Spires

12

Sürüm listeleri üzerinde yinelemeye gerek yok. Listelerdeki ve kayıtlardaki yerleşik karşılaştırma operatörü zaten tam istediğiniz gibi çalışır. Sadece sürüm listelerini karşılık gelen uzunluğa sıfırlamanız gerekir. Python 2.6 ile dizileri doldurmak için izip_longest kullanabilirsiniz.

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)

Daha düşük sürümlerde, bazı harita korsanlığı gereklidir.

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)

Harika, ancak nesir gibi kodu okuyamayan biri için anlaşılması zor. :) Çözümü yalnızca okunabilirlik pahasına kısaltabileceğinizi varsayıyorum ...
Johannes Charra

10

Bu, önerinizden biraz daha derli toplu. Daha kısa sürümü sıfırlarla doldurmak yerine, böldükten sonra sürüm listelerinden sondaki sıfırları kaldırıyorum.

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))

İyiydi, teşekkürler. Ama yine de bir ya da iki astar bekliyorum ...;)
Johannes Charra

4
+1 @jellybean: iki satırlılar her zaman bakım ve okunabilirlik için en iyisi değildir, bu aynı zamanda çok açık ve kompakt bir koddur, ayrıca mycmpihtiyacınız olması durumunda kodunuzda başka amaçlar için tekrar kullanabilirsiniz .
RedGlyph

@RedGlyph: Orada bir noktaya varmışsın. "Okunabilir iki satırlı" demeliydim. :)
Johannes Charra

hi @ Pär Wieslander, Leetcode probleminde aynı sorunu çözmek için bu çözümü kullandığımda while döngüsünde "list dizini aralık dışı" diyen bir hata alıyorum. Bunun neden oluştuğuna lütfen yardım edebilir misiniz? Sorun şu: leetcode.com/explore/interview/card/amazon/76/array-and-strings/…
YouHaveaBigEgo

7

Sonu .0ve .00normal ifadeyi kaldırın ve dizileri doğru şekilde karşılaştıran işlevi splitkullanın 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)

Ve tabii ki, uzun çizgileri önemsemiyorsanız onu tek astara dönüştürebilirsiniz.


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('.')]))))

Tek satırlıktır (okunabilirlik için bölünmüş). Okunabilir olduğundan emin değilim ...


1
Evet! Ve daha da küçüldü ( tuplebtw gerekli değil):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"=" Dışında php için uygulama . Çünkü belirsiz.


2

Listeler Python'da karşılaştırılabilir, bu nedenle biri sayıları temsil eden dizeleri tam sayılara dönüştürürse, temel Python karşılaştırması başarıyla kullanılabilir.

Bu yaklaşımı biraz genişletmem gerekiyordu çünkü Python3x'i cmpfonksiyonun artık mevcut olmadığı yerlerde kullanıyorum . Ben taklit zorunda cmp(a,b)olan (a > b) - (a < b). Ve sürüm numaraları o kadar da net değildir ve her türlü diğer alfanümerik karakter içerebilir. İşlevin sırayı söyleyemediği ve böylece geri döndüğü durumlar vardır False(ilk örneğe bakın).

Bu yüzden, soru eski olsa ve cevaplanmış olsa bile bunu gönderiyorum, çünkü birinin hayatında birkaç dakika kazandırabilir.

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

Harici bir bağımlılık çekmek istemiyorsanız, işte benim girişim Python 3.x için yazılmıştır.

rc, rel(ve muhtemelen eklenebilir c) "yayın adayı" olarak kabul edilir ve sürüm numarasını iki kısma böler ve eğer ikinci parçanın değeri eksikse (999) yüksektir. Başka harfler bir bölme oluşturur ve 36 taban kodu aracılığıyla alt numaralar olarak dağıtılır.

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

Okuması en zor çözüm, ancak yine de tek satırlık! ve hızlı olmak için yineleyiciler kullanmak.

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)

yani Python2.6 ve 3. + btw içindir, Python 2.5 ve daha eski sürümler StopIteration'ı yakalamalıdır.


1

Bunu Debian paketi sürüm dizesini ayrıştırıp karşılaştırabilmek için yaptım. Lütfen karakter doğrulamasının katı olmadığını unutmayın.

Bu da yardımcı olabilir:

#!/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

Başka bir çözüm:

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))

Bunun gibi de kullanılabilir:

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

Yıllar sonra, ama yine de bu soru en üstte.

İşte benim sürüm sıralama fonksiyonum. Sürümü sayılara ve sayı olmayan bölümlere ayırır. Sayılar intgeri kalanı olarak karşılaştırılır str(liste öğelerinin parçaları olarak).

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))

Karşılaştırma işleçleriyle işlevi keyözel bir tür olarak kullanabilirsiniz Version. Gerçekten kullanmak cmpistiyorsanız, bu örnekteki gibi yapabilirsiniz: https://stackoverflow.com/a/22490617/9935708

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

Test paketi geçer.


-1

Tercih ettiğim çözüm:

Dizeyi fazladan sıfırlarla doldurmak ve sadece ilk dördünü kullanmak anlaşılması kolaydır, herhangi bir normal ifade gerektirmez ve lambda az çok okunabilir. Okunabilirlik için iki satır kullanıyorum, benim için zarafet kısa ve basit.

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

Bu benim çözümüm (C ile yazılmış, üzgünüm). Umarım faydalı bulursun

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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.