उद्देश्य-सी में संस्करण संख्याओं की तुलना करें


87

मैं एक एप्लिकेशन लिख रहा हूं जो आइटम और संस्करण संख्याओं के साथ डेटा प्राप्त करता है। संख्या "1.0.1" या "1.2.5" की तरह स्वरूपित हैं। मैं इन संस्करण संख्याओं की तुलना कैसे कर सकता हूं? मुझे लगता है कि उन्हें पहले एक स्ट्रिंग के रूप में प्रारूपित करना होगा, नहीं? मुझे यह निर्धारित करने के लिए कि "1.2.5" के बाद क्या विकल्प मिलते हैं?


मैंने लिखा है कि छोटे पुस्तकालय आसानी से ओबज-सी में 2 संस्करणों की तुलना करें। आमतौर पर आईओएस में। GitHub पेज
nembleton

3
यह ठीक से स्पष्ट करने में मदद करता है कि संस्करण योजना क्या है। कुछ के पास अतिरिक्त तर्क की आवश्यकता वाले प्रारूप हो सकते हैं।
uchuugaka

जवाबों:


244

संस्करणों की तुलना करने का यह सबसे सरल तरीका है, यह ध्यान में रखते हुए कि "1" <"1.0" <"1.0.0":

NSString* requiredVersion = @"1.2.0";
NSString* actualVersion = @"1.1.5";

if ([requiredVersion compare:actualVersion options:NSNumericSearch] == NSOrderedDescending) {
  // actualVersion is lower than the requiredVersion
}

6
मैं इस विधि का उपयोग कर रहा था, और मैंने हाल ही में पाया कि यह (जो मैं विचार करता हूं) गलत परिणाम देता है जब तुलना करते हैं: 2.4.06 2.4.4 के साथ। मेरा मानना ​​है कि 2.4.06 2.4.4 से कम होना चाहिए, लेकिन शायद मैं गलत हूं ... कोई विचार?
ओमेर

7
@ उम: क्यों 06 और 6 नहीं? मुझे लगता है कि अधिकांश डेवलपर्स 2.4.4 से उच्चतर संस्करण के लिए 2.4.06 पर विचार करेंगे।
स्टीफन मेल्विन

4
यह अच्छा और सरल है लेकिन एक बहुत ही सरल संस्करण योजना पर निर्भर करता है।
uchuugaka

11
@ScottBerrevoets मैं निश्चित रूप से आशा करता हूँ कि यह कैसे काम करता है, क्योंकि इसका अर्थ "1.2.3" "1.1.12" (123 <1112) से कम नहीं होगा! जैसा कि Apple ध्यान से बताता है, " स्ट्रिंग्स के भीतर संख्याओं की तुलना संख्यात्मक मान का उपयोग करके की जाती है "। यही है, तारों के भीतर संख्याओं के सेट की तुलना (अनिवार्य रूप से, componentsSeparatedByStringदृष्टिकोण) से की जाएगी। आप अपने आप को @"1.8"बनाम के साथ परीक्षण कर सकते @"1.7.2.3.55"हैं और देख सकते हैं कि 1.8 आगे निकलता है।
डोलियो

3
NSNumericSearch को लगता है कि "1.0" "1.0.0" से कम है। मेरे उद्देश्यों के लिए पर्याप्त लचीला नहीं है।
बॉब

17

मैं अपने तरीके को जोड़ूंगा, जो किसी भी संख्या के घटकों के साथ कड़ाई से संख्यात्मक संस्करणों (नहीं, बी, आरसी आदि) की तुलना करता है।

+ (NSComparisonResult)compareVersion:(NSString*)versionOne toVersion:(NSString*)versionTwo {
    NSArray* versionOneComp = [versionOne componentsSeparatedByString:@"."];
    NSArray* versionTwoComp = [versionTwo componentsSeparatedByString:@"."];

    NSInteger pos = 0;

    while ([versionOneComp count] > pos || [versionTwoComp count] > pos) {
        NSInteger v1 = [versionOneComp count] > pos ? [[versionOneComp objectAtIndex:pos] integerValue] : 0;
        NSInteger v2 = [versionTwoComp count] > pos ? [[versionTwoComp objectAtIndex:pos] integerValue] : 0;
        if (v1 < v2) {
            return NSOrderedAscending;
        }
        else if (v1 > v2) {
            return NSOrderedDescending;
        }
        pos++;
    }

    return NSOrderedSame;
}

13

यह 1 <1.0 <1.0.0 आदि की समस्या को हल करने के लिए नाथन डी वीर्स के उत्तर का विस्तार है।

सबसे पहले हम एक NSStringश्रेणी के साथ हमारे संस्करण स्ट्रिंग पर अतिरिक्त ".0" की समस्या का समाधान कर सकते हैं :

@implementation NSString (VersionNumbers)
- (NSString *)shortenedVersionNumberString {
    static NSString *const unnecessaryVersionSuffix = @".0";
    NSString *shortenedVersionNumber = self;

    while ([shortenedVersionNumber hasSuffix:unnecessaryVersionSuffix]) {
        shortenedVersionNumber = [shortenedVersionNumber substringToIndex:shortenedVersionNumber.length - unnecessaryVersionSuffix.length];
    }

    return shortenedVersionNumber;
}
@end

उपरोक्त NSStringश्रेणी के साथ हम अनावश्यक .0 को छोड़ने के लिए अपने संस्करण संख्या को छोटा कर सकते हैं

NSString* requiredVersion = @"1.2.0";
NSString* actualVersion = @"1.1.5";

requiredVersion = [requiredVersion shortenedVersionNumberString]; // now 1.2
actualVersion = [actualVersion shortenedVersionNumberString]; // still 1.1.5

अब हम नातान डे व्रीस द्वारा प्रस्तावित सुंदर सरल दृष्टिकोण का उपयोग कर सकते हैं:

if ([requiredVersion compare:actualVersion options:NSNumericSearch] == NSOrderedDescending) {
  // actualVersion is lower than the requiredVersion
}

नाथन डी वीर्स समाधान के साथ युग्मित यह सबसे अच्छा और सबसे सुंदर जवाब है।
दालमाज़ियो

क्या यह अभी भी नहीं कहेगा कि 7.4.2 7.5 से अधिक संस्करण है?
ट्रेस

@ ट्रेस नं। क्योंकि NSNumericSearch को विकल्प के रूप में पारित किया जाता है, तार की संख्या के रूप में तुलना की जाती है, इस प्रकार 7.4.2 <7.5
DonnaLea

9

मैंने इसे खुद बनाया है, श्रेणी का उपयोग करें।

स्रोत ..

@implementation NSString (VersionComparison)
- (NSComparisonResult)compareVersion:(NSString *)version{
    NSArray *version1 = [self componentsSeparatedByString:@"."];
    NSArray *version2 = [version componentsSeparatedByString:@"."];
    for(int i = 0 ; i < version1.count || i < version2.count; i++){
        NSInteger value1 = 0;
        NSInteger value2 = 0;
        if(i < version1.count){
            value1 = [version1[i] integerValue];
        }
        if(i < version2.count){
            value2 = [version2[i] integerValue];
        }
        if(value1  == value2){
            continue;
        }else{
            if(value1 > value2){
                return NSOrderedDescending;
            }else{
                return NSOrderedAscending;
            }
        }
    }
    return NSOrderedSame;
}

परीक्षा..

NSString *version1 = @"3.3.1";
NSString *version2 = @"3.12.1";
NSComparisonResult result = [version1 compareVersion:version2];
switch (result) {
    case NSOrderedAscending:
    case NSOrderedDescending:
    case NSOrderedSame:
         break;
    }

बहुत बढ़िया! इस सूत्र पर NSComparisonResult का उपयोग करने वाला एकमात्र उदाहरण है जो 7.28.2 और 7.28 की तुलना सही ढंग से करता है।
कोकपोकस

8

स्पार्कल (MacOS के लिए सबसे लोकप्रिय सॉफ्टवेयर अपडेट फ्रेमवर्क) में SUStandardVersionComparator वर्ग है जो ऐसा करता है, और बिल्ड बिल्ड नंबर और बीटा मार्कर को भी ध्यान में रखता है। यानी यह सही तरह से तुलना करता है 1.0.5 > 1.0.5b7या 2.0 (2345) > 2.0 (2100)। कोड केवल फाउंडेशन का उपयोग करता है, इसलिए आईओएस पर भी ठीक काम करना चाहिए।


6

मेरे NSString श्रेणी की जाँच करें जो कि जीथब पर आसान संस्करण की जाँच को लागू करता है; https://github.com/stijnster/NSString-compareToVersion

[@"1.2.2.4" compareToVersion:@"1.2.2.5"];

यह एक NSComparisonResult लौटाएगा जो अधिक सटीक है फिर उपयोग करना;

[@"1.2.2" compare:@"1.2.2.5" options:NSNumericSearch]

सहायकों को भी जोड़ा जाता है;

[@"1.2.2.4" isOlderThanVersion:@"1.2.2.5"];
[@"1.2.2.4" isNewerThanVersion:@"1.2.2.5"];
[@"1.2.2.4" isEqualToVersion:@"1.2.2.5"];
[@"1.2.2.4" isEqualOrOlderThanVersion:@"1.2.2.5"];
[@"1.2.2.4" isEqualOrNewerThanVersion:@"1.2.2.5"];

4

स्विफ्ट 2.2 संस्करण:

let currentStoreAppVersion = "1.10.2"
let minimumAppVersionRequired = "1.2.2"
if currentStoreAppVersion.compare(minimumAppVersionRequired, options: NSStringCompareOptions.NumericSearch) ==
            NSComparisonResult.OrderedDescending {
            print("Current Store version is higher")
        } else {
            print("Latest New version is higher")
        }

स्विफ्ट 3 संस्करण:

let currentStoreVersion = "1.1.0.2"
let latestMinimumAppVersionRequired = "1.1.1"
if currentStoreVersion.compare(latestMinimumAppVersionRequired, options: NSString.CompareOptions.numeric) == ComparisonResult.orderedDescending {
print("Current version is higher")
} else {
print("Latest version is higher")
}

4

यहां संस्करण तुलना के लिए स्विफ्ट 4.0 + कोड है

 let currentVersion = "1.2.0"

 let oldVersion = "1.1.1"

 if currentVersion.compare(oldVersion, options: NSString.CompareOptions.numeric) == ComparisonResult.orderedDescending {
        print("Higher")
    } else {
        print("Lower")
    }

3

मैंने सोचा कि मैं सिर्फ एक समारोह साझा करूँगा जो मैंने इसके लिए एक साथ खींचा था। यह बिल्कुल सही नहीं है। कृपया उदाहरण और परिणाम देखें। लेकिन अगर आप अपने स्वयं के संस्करण संख्याओं की जाँच कर रहे हैं (जो मुझे डेटाबेस माइग्रेशन जैसी चीज़ों को प्रबंधित करने के लिए करना है) तो इससे थोड़ी मदद मिल सकती है।

(यह भी, विधि में लॉग बयानों को हटा दें, निश्चित रूप से। वे वहां हैं जो आपको यह देखने में मदद करने के लिए हैं कि यह क्या करता है)

टेस्ट:

[self isVersion:@"1.0" higherThan:@"0.1"];
[self isVersion:@"1.0" higherThan:@"0.9.5"];
[self isVersion:@"1.0" higherThan:@"0.9.5.1"];
[self isVersion:@"1.0.1" higherThan:@"1.0"];
[self isVersion:@"1.0.0" higherThan:@"1.0.1"];
[self isVersion:@"1.0.0" higherThan:@"1.0.0"];

// alpha tests
[self isVersion:@"1.0b" higherThan:@"1.0a"];
[self isVersion:@"1.0a" higherThan:@"1.0b"];
[self isVersion:@"1.0a" higherThan:@"1.0a"];
[self isVersion:@"1.0" higherThan:@"1.0RC1"];
[self isVersion:@"1.0.1" higherThan:@"1.0RC1"];

परिणाम:

1.0 > 0.1
1.0 > 0.9.5
1.0 > 0.9.5.1
1.0.1 > 1.0
1.0.0 < 1.0.1
1.0.0 == 1.0.0
1.0b > 1.0a
1.0a < 1.0b
1.0a == 1.0a
1.0 < 1.0RC1       <-- FAILURE
1.0.1 < 1.0RC1     <-- FAILURE

ध्यान दें कि अल्फा काम करता है लेकिन आपको इसके साथ बहुत सावधान रहना होगा। एक बार जब आप किसी बिंदु पर अल्फा जाते हैं, तो आप इसके पीछे किसी भी अन्य छोटी संख्या को बदलकर विस्तार नहीं कर सकते।

कोड:

- (BOOL) isVersion:(NSString *)thisVersionString higherThan:(NSString *)thatVersionString {

// LOWER
if ([thisVersionString compare:thatVersionString options:NSNumericSearch] == NSOrderedAscending) {
    NSLog(@"%@ < %@", thisVersionString, thatVersionString);
    return NO;
}

// EQUAL
if ([thisVersionString compare:thatVersionString options:NSNumericSearch] == NSOrderedSame) {
    NSLog(@"%@ == %@", thisVersionString, thatVersionString);
    return NO;
}

NSLog(@"%@ > %@", thisVersionString, thatVersionString);
// HIGHER
return YES;
}

3

मेरी iOS लाइब्रेरी AppUpdateTracker में इस प्रकार की तुलना करने के लिए एक NSString श्रेणी है। (कार्यान्वयन डोनालेआ के उत्तर पर आधारित है ।)

उपयोग निम्नानुसार होगा:

[@"1.4" isGreaterThanVersionString:@"1.3"]; // YES
[@"1.4" isLessThanOrEqualToVersionString:@"1.3"]; // NO

इसके अतिरिक्त, आप इसे अपने ऐप की स्थापना / अद्यतन स्थिति का ट्रैक रखने के लिए उपयोग कर सकते हैं:

[AppUpdateTracker registerForAppUpdatesWithBlock:^(NSString *previousVersion, NSString *currentVersion) {
    NSLog(@"app updated from: %@ to: %@", previousVersion, currentVersion);
}];
[AppUpdateTracker registerForFirstInstallWithBlock:^(NSTimeInterval installTimeSinceEpoch, NSUInteger installCount) {
    NSLog(@"first install detected at: %f amount of times app was (re)installed: %lu", installTimeSinceEpoch, (unsigned long)installCount);
}];
[AppUpdateTracker registerForIncrementedUseCountWithBlock:^(NSUInteger useCount) {
    NSLog(@"incremented use count to: %lu", (unsigned long)useCount);
}];

v4.21 <4.3 है? अगर ([thisVersion isGraitThanOrEqualToVersionString: @ "4.3"])
जॉन्डपोप

नहीं, 4.21 को 4.3 से अधिक 21> 3 माना जाता है। 3. अपनी समानता की तुलना को संतुष्ट करने के लिए, आप 4.21 की तुलना 4.30 से करना चाहेंगे। कृपया नातान डे व्रस के उत्तर की टिप्पणियों में चर्चा देखें ।
स्टनर

0

Glibc का एक कार्य है strverscmpऔर versionsort... दुर्भाग्य से, iPhone के लिए पोर्टेबल नहीं है, लेकिन आप अपने स्वयं के काफी आसानी से लिख सकते हैं। यह (अप्रकाशित) पुन: कार्यान्वयन केवल प्रलेखित व्यवहार को पढ़ने से आता है, न कि ग्लिबक के स्रोत कोड को पढ़ने से।

int strverscmp(const char *s1, const char *s2) {
    const char *b1 = s1, *b2 = s2, *e1, *e2;
    long n1, n2;
    size_t z1, z2;
    while (*b1 && *b1 == *b2) b1++, b2++;
    if (!*b1 && !*b2) return 0;
    e1 = b1, e2 = b2;
    while (b1 > s1 && isdigit(b1[-1])) b1--;
    while (b2 > s2 && isdigit(b2[-1])) b2--;
    n1 = strtol(b1, &e1, 10);
    n2 = strtol(b2, &e2, 10);
    if (b1 == e1 || b2 == e2) return strcmp(s1, s2);
    if (n1 < n2) return -1;
    if (n1 > n2) return 1;
    z1 = strspn(b1, "0"), z2 = strspn(b2, "0");
    if (z1 > z2) return -1;
    if (z1 < z2) return 1;
    return 0;
}

2
यह सिर्फ भयानक लग रहा है। ऑब्जेक्टिव-सी के बारे में जो चीजें मुझे सबसे ज्यादा पसंद हैं, उनमें से एक यह है कि ज्यादातर हिस्से के लिए मुझे अब प्लेन सी से जूझना नहीं पड़ेगा।
लुकास पेट्र

0

यदि आप जानते हैं कि प्रत्येक संस्करण संख्या में डॉट्स द्वारा अलग-अलग 3 पूर्णांक होंगे, तो आप उन्हें पार्स कर सकते हैं (उदाहरण के लिए sscanf(3)) और उनकी तुलना करें:

const char *version1str = "1.0.1";
const char *version2str = "1.2.5";
int major1, minor1, patch1;
int major2, minor2, patch2;
if(sscanf(version1str, "%d.%d.%d", &major1, &minor1, &patch1) == 3 &&
   sscanf(version2str, "%d.%d.%d", &major2, &minor2, &patch2) == 3)
{
    // Parsing succeeded, now compare the integers
    if(major1 > major2 ||
      (major1 == major2 && (minor1 > minor2 ||
                           (minor1 == minor2 && patch1 > patch2))))
    {
        // version1 > version2
    }
    else if(major1 == major2 && minor1 == minor2 && patch1 == patch2)
    {
        // version1 == version2
    }
    else
    {
        // version1 < version2
    }
}
else
{
    // Handle error, parsing failed
}

0

स्विफ्ट में संस्करण की जांच करने के लिए आप निम्नलिखित का उपयोग कर सकते हैं

switch newVersion.compare(currentversion, options: NSStringCompareOptions.NumericSearch) {
    case .OrderedDescending:
        println("NewVersion available  ")
        // Show Alert Here

    case .OrderedAscending:
        println("NewVersion Not available  ")
    default:
        println("default")
    }

आशा है कि यह मददगार हो सकता है।


0

यहाँ एक पुनरावर्ती कार्य है जो किसी भी लम्बाई के कई संस्करण स्वरूपण के साथ काम करता है। यह @ "1.0" और @ "1.0.0" के लिए भी काम करता है

static inline NSComparisonResult versioncmp(const NSString * a, const NSString * b)
{
    if ([a isEqualToString:@""] && [b isEqualToString:@""]) {
        return NSOrderedSame;
    }

    if ([a isEqualToString:@""]) {
        a = @"0";
    }

    if ([b isEqualToString:@""]) {
        b = @"0";
    }

    NSArray<NSString*> * aComponents = [a componentsSeparatedByString:@"."];
    NSArray<NSString*> * bComponents = [b componentsSeparatedByString:@"."];
    NSComparisonResult r = [aComponents[0] compare:bComponents[0] options:NSNumericSearch];

    if(r != NSOrderedSame) {
        return r;
    } else {
        NSString* newA = (a.length == aComponents[0].length) ? @"" : [a substringFromIndex:aComponents[0].length+1];
        NSString* newB = (b.length == bComponents[0].length) ? @"" : [b substringFromIndex:bComponents[0].length+1];
        return versioncmp(newA, newB);
    }

}

परीक्षण के नमूने:

versioncmp(@"11.5", @"8.2.3");
versioncmp(@"1.5", @"8.2.3");
versioncmp(@"1.0", @"1.0.0");
versioncmp(@"11.5.3.4.1.2", @"11.5.3.4.1.2");
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.