पायथन में संस्करण संख्या की तुलना


98

मैं एक लिखना चाहते हैं cmpकी तरह समारोह जो दो संस्करण संख्याओं और रिटर्न तुलना -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

मैं अजगर 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

उत्तर नहीं है, लेकिन एक सुझाव है - यह संस्करण संख्या की तुलना के लिए डेबियन के एल्गोरिथ्म को लागू करने के लायक हो सकता है (मूल रूप से, गैर-संख्यात्मक और संख्यात्मक भागों की वैकल्पिक छँटाई)। यहां एल्गोरिदम का वर्णन किया गया है ("स्ट्रिंग्स की तुलना बाएं से दाएं की ओर की गई है")।
हॉब्स

Blargh। टिप्पणियों में समर्थित मार्कडाउन का सबसेट मुझे भ्रमित करने में कभी विफल नहीं होता है। लिंक वैसे भी काम करता है, भले ही वह बेवकूफ लग रहा हो।
हॉब्स

यदि भविष्य के पाठकों को उपयोगकर्ता-एजेंट संस्करण पार्सिंग के लिए इसकी आवश्यकता है, तो मैं एक समर्पित पुस्तकालय को ऐतिहासिक बदलाव के रूप में सुझाता हूं ।
जेम्स ब्रॉडहेड


1
भले ही यहाँ प्रश्न अधिक पुराना है, यह प्रतीत होता है कि इस अन्य प्रश्न का विहित के रूप में अभिषेक किया गया है, कई, कई प्रश्न उस एक के डुप्लिकेट के रूप में बंद हैं।
जॉन वाई

जवाबों:


36

स्ट्रिंग (अनुगामी शून्य और डॉट्स) के निर्बाध भाग को निकालें, और फिर संख्याओं की सूची की तुलना करें।

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 के समान है, लेकिन थोड़ा अधिक कॉम्पैक्ट है:

यहां कुछ परीक्षण दिए गए हैं, " बैश में डॉट सेपरेटेड वर्जन फॉर्मेट में दो स्ट्रिंग्स की तुलना कैसे करें? "

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")".10" को ".1" में "1.0.10" में बदल देगा।
RedGlyph

क्षमा करें, लेकिन अपने कार्य के साथ: mycmp ( '1.1', '1.10') == 0
जोहानिस Charra

रेगेक्स के उपयोग के साथ, ऊपर वर्णित समस्या तय हो गई है।
१६:३०

अब आप अपने समाधान में दूसरों से सभी अच्छे विचारों का विलय कर चुके हैं ...: -पी फिर भी, यह बहुत ज्यादा है कि मैं आखिर क्या करूंगा। मैं इस उत्तर को स्वीकार करूंगा। धन्यवाद, हर कोई
जोहान्स चार

2
नोट cmp () को पायथन 3 में हटा दिया गया है: docs.python.org/3.0/whatsnew/3.0.html#ordering-comparison
डोमिनिक क्ले

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

इस नस्ल के साथ सफलता के लिए, आपको मानक पुस्तकालय के बाहर कदम रखना होगा और सेटपूल के पार्सिंग उपयोगिता का उपयोग करना होगा parse_version

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

इसलिए आपके विशिष्ट उपयोग के मामले के आधार पर, आपको यह तय करने की आवश्यकता होगी कि क्या अंतर्निहित distutilsउपकरण पर्याप्त हैं, या यदि यह निर्भरता के रूप में जोड़ने के लिए वारंट किया गया है setuptools


2
लगता है कि सबसे पहले उपयोग करने के लिए सबसे ज्यादा समझ में आता है :)
पैट्रिक वुल्फ

2
अच्छा! क्या आपने स्रोत पढ़कर यह पता लगाया? मैं डिस्टुटिल्स के लिए डॉक्स नहीं पा सकता हूं। कहीं भी: - /
एडम स्पियर्स

3
किसी भी समय आप दस्तावेज़ नहीं ढूंढ सकते हैं, पैकेज आयात करने की कोशिश करें और मदद का उपयोग करें ()।
rspeed

13
हालाँकि, अवगत रहें कि StrictVersion केवल तीन नंबर संस्करण के साथ काम करता है। यह चीजों की तरह विफल रहता है 0.4.3.6!
abergmeier

6
distributeइस उत्तर के प्रत्येक उदाहरण को प्रतिस्थापित किया जाना चाहिए setuptools, जो pkg_resourcesपैकेज के साथ बंडल में आता है और तब से ... जैसे, कभी भी । इसी तरह, यह हैpkg_resources.parse_version() बंडल के साथ फंक्शन के लिए आधिकारिक दस्तावेज हैsetuptools
सेसिल करी

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 शामिल करने के लिए एक संपादन सबमिट किया है। व्यक्तिगत रूप से मैं डिस्टिल्स का उपयोग करना पसंद करता हूं - यह इतना आसान काम के लिए 3 पार्टी सॉफ्टवेयर में खींचने के प्रयास के लायक नहीं लगता है।
एडम स्पियर्स

1
@ एडाम-स्पियर्स वूट? क्या आपने कमेंट्री भी पढ़ी? pkg_resourcesएक setuptoolsबंद पैकेज है। चूंकि setuptoolsसभी पायथन प्रतिष्ठानों पर प्रभावी रूप से अनिवार्य है, pkg_resourcesहर जगह प्रभावी रूप से उपलब्ध है। उस ने कहा, सब- distutils.versionपैकेज भी उपयोगी है - हालांकि उच्च-स्तरीय pkg_resources.parse_version()फ़ंक्शन की तुलना में काफी कम बुद्धिमान । जिसका आपको लाभ उठाना चाहिए यह इस बात पर निर्भर करता है कि आप संस्करण स्ट्रिंग में किस हद तक पागलपन की उम्मीद करते हैं।
सेसिल करी

@CecilCurry हाँ बेशक मैंने टिप्पणी (एरी) पढ़ी, यही वजह है कि मैंने इसे बेहतर बनाने के लिए इसे संपादित किया, और फिर कहा कि मेरे पास था। संभवतः आप मेरे बयान से असहमत नहीं हैं setuptoolsजो मानक पुस्तकालय के बाहर है, और इसके बजाय distutils इस मामले में मेरी घोषित प्राथमिकता के साथ । तो क्या आप वास्तव में "प्रभावी रूप से अनिवार्य" से मतलब रखते हैं, और क्या आप साक्ष्य प्रदान कर सकते हैं कि यह "प्रभावी रूप से अनिवार्य" था 4.5 साल पहले जब मैंने यह टिप्पणी लिखी थी?
एडम स्पीयर्स 15

12

संस्करण tuples पर पुनरावृति करने की आवश्यकता नहीं है। सूचियों और टुपल्स पर तुलना ऑपरेटर में बनाया पहले से ही ठीक वैसे ही काम करता है जैसे आप चाहते हैं। आपको केवल संस्करण सूचियों को इसी लंबाई तक शून्य करने की आवश्यकता होगी। अजगर 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)

कूल, लेकिन किसी के लिए समझना मुश्किल है जो गद्य जैसे कोड को नहीं पढ़ सकता है। :) ठीक है, मुझे लगता है कि आप केवल पठनीयता की कीमत पर समाधान को छोटा कर सकते हैं ...
जोहान्स चररा

10

यह आपके सुझाव से थोड़ा अधिक कॉम्पैक्ट है। शून्य संस्करण के साथ छोटे संस्करण को भरने के बजाय, मैं विभाजित करने के बाद संस्करण सूची से ट्रेलिंग शून्य हटा रहा हूं।

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 @ जेलीबीन: रखरखाव और पठनीयता के लिए दो-लाइनर हमेशा सर्वश्रेष्ठ नहीं होते हैं, यह एक ही समय में बहुत स्पष्ट और कॉम्पैक्ट कोड है, इसके अलावा, आपको mycmpअपने कोड में अन्य उद्देश्यों के लिए फिर से उपयोग करना चाहिए जो आपको चाहिए।
RedGlyph

@RedGlyph: आपको वहां एक बिंदु मिल गया है। कहना चाहिए था "एक पठनीय दो-लाइनर"। :)
जोहान्स चरारा

hi @ Pär Wieslander, जब मैं Leetcode समस्या पर उसी समस्या को हल करने के लिए इस समाधान का उपयोग करता हूं, तो मुझे लूप में एक त्रुटि मिलती है, जिसमें कहा जाता है "सूची सूचकांक सीमा से बाहर"। क्या आप कृपया मदद कर सकते हैं कि ऐसा क्यों होता है? यहाँ समस्या है: leetcode.com/explore/interview/card/amazon/76/array-and-strings/…
YouHaveaBigEgo

7

ट्रेलिंग निकालें .0और .00regex के साथ, 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('.')) )))
पॉल

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

पाइथन में सूचियाँ तुलनीय हैं, इसलिए यदि कोई संख्याओं का प्रतिनिधित्व करने वाले तारों को पूर्णांकों में परिवर्तित करता है, तो मूल पायथन तुलना का उपयोग सफलता के साथ किया जा सकता है।

मुझे इस दृष्टिकोण को थोड़ा विस्तारित करने की आवश्यकता थी क्योंकि मैं पायथन 3 एक्स का उपयोग करता हूं जहां cmpफ़ंक्शन का कोई अस्तित्व नहीं है। मुझे 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

यदि आप एक बाहरी निर्भरता में नहीं खींचना चाहते हैं तो मेरी कोशिश पायथन 3.x के लिए लिखी गई है।

rc, rel(और संभवतः एक जोड़ सकता है c) को "रिलीज़ उम्मीदवार" के रूप में माना जाता है और संस्करण संख्या को दो भागों में विभाजित करता है और यदि दूसरे भाग का मान उच्च है (999)। आधार पत्र एक विभाजन उत्पन्न करते हैं और आधार -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

वर्षों बाद, लेकिन यह सवाल सबसे ऊपर है।

यहां मेरा संस्करण सॉर्ट फ़ंक्शन है। यह संख्याओं और गैर-संख्या वर्गों में संस्करण को विभाजित करता है। संख्या की तुलना 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प्रकार के प्रकार के रूप में फ़ंक्शन का उपयोग कर सकते हैं । अगर वास्तव में cmpआप इसका उपयोग करना चाहते हैं, तो इस उदाहरण में कर सकते हैं: https://stackoverflow.com/a/22490617/535358

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

मेरा पसंदीदा समाधान:

अतिरिक्त शून्य के साथ स्ट्रिंग को पैडिंग करना और केवल पहले चार का उपयोग करना समझना आसान है, किसी भी रेगेक्स की आवश्यकता नहीं है और लैम्ब्डा अधिक या कम पठनीय है। मैं पठनीयता के लिए दो पंक्तियों का उपयोग करता हूं, मेरे लिए लालित्य छोटा और सरल है।

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

यह मेरा समाधान है (सी में लिखा है, क्षमा करें)। मुझे आशा है कि आप इसे उपयोगी पाएंगे

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;
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.