J'écris une application qui reçoit des données avec des éléments et des numéros de version. Les nombres sont au format "1.0.1" ou "1.2.5". Comment puis-je comparer ces numéros de version? Je pense qu'ils doivent d'abord être formatés sous forme de chaîne, non? Quelles options ai-je pour déterminer que "1.2.5" vient après "1.0.1"?
objective-c
comparison
mlecho
la source
la source
Réponses:
C'est le moyen le plus simple de comparer les versions, en gardant à l'esprit que "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 }
la source
componentsSeparatedByString
approche). Vous pouvez le tester vous-même avec@"1.8"
vs@"1.7.2.3.55"
et voir que la 1.8 sort en tête.J'ajouterai ma méthode, qui compare les versions strictement numériques (pas de a, b, RC etc.) avec n'importe quel nombre de composants.
+ (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; }
la source
Il s'agit d'une extension de la réponse de Nathan de Vries pour résoudre le problème de 1 <1.0 <1.0.0 etc.
Tout d'abord, nous pouvons résoudre le problème des ".0" supplémentaires sur notre chaîne de version avec une
NSString
catégorie:@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
Avec la
NSString
catégorie ci-dessus , nous pouvons raccourcir nos numéros de version pour supprimer les .0 inutilesNSString* requiredVersion = @"1.2.0"; NSString* actualVersion = @"1.1.5"; requiredVersion = [requiredVersion shortenedVersionNumberString]; // now 1.2 actualVersion = [actualVersion shortenedVersionNumberString]; // still 1.1.5
Maintenant, nous pouvons toujours utiliser l'approche magnifiquement simple proposée par Nathan de Vries:
if ([requiredVersion compare:actualVersion options:NSNumericSearch] == NSOrderedDescending) { // actualVersion is lower than the requiredVersion }
la source
Je l'ai fait moi-même, utilisez Category.
La source..
@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; }
Tester..
NSString *version1 = @"3.3.1"; NSString *version2 = @"3.12.1"; NSComparisonResult result = [version1 compareVersion:version2]; switch (result) { case NSOrderedAscending: case NSOrderedDescending: case NSOrderedSame: break; }
la source
Sparkle (le framework de mise à jour logicielle le plus populaire pour MacOS) a une classe SUStandardVersionComparator qui fait cela, et prend également en compte les numéros de build et les marqueurs bêta. Ie il compare correctement
1.0.5 > 1.0.5b7
ou2.0 (2345) > 2.0 (2100)
. Le code utilise uniquement Foundation, il devrait donc fonctionner correctement sur iOS également.la source
Consultez ma catégorie NSString qui implémente une vérification de version facile sur github; https://github.com/stijnster/NSString-compareToVersion
[@"1.2.2.4" compareToVersion:@"1.2.2.5"];
Cela renverra un NSComparisonResult qui est plus précis que l'utilisation;
[@"1.2.2" compare:@"1.2.2.5" options:NSNumericSearch]
Des aides sont également ajoutées;
[@"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"];
la source
Version Swift 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") }
Version Swift 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") }
la source
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") }
la source
Je pensais que je partagerais juste une fonction que j'ai organisée pour cela. Ce n'est pas du tout parfait. Veuillez jeter un œil aux exemples et résultats. Mais si vous vérifiez vos propres numéros de version (ce que je dois faire pour gérer des choses comme les migrations de bases de données), cela peut aider un peu.
(aussi, supprimez les instructions de journal dans la méthode, bien sûr. celles-ci sont là pour vous aider à voir ce qu'elle fait, c'est tout)
Tests:
[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"];
Résultats:
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
notez que alpha fonctionne mais vous devez être très prudent avec cela. une fois que vous passez à l'alpha à un moment donné, vous ne pouvez pas étendre cela en changeant d'autres nombres mineurs derrière.
Code:
- (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; }
la source
Ma bibliothèque iOS AppUpdateTracker contient une catégorie NSString pour effectuer ce genre de comparaison. (La mise en œuvre est basée sur la réponse de DonnaLea .)
L'utilisation serait la suivante:
[@"1.4" isGreaterThanVersionString:@"1.3"]; // YES [@"1.4" isLessThanOrEqualToVersionString:@"1.3"]; // NO
De plus, vous pouvez l'utiliser pour suivre l'état d'installation / de mise à jour de votre application:
[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); }];
la source
Glibc a une fonction
strverscmp
etversionsort
... malheureusement, pas portable sur l'iPhone, mais vous pouvez écrire la vôtre assez facilement. Cette réimplémentation (non testée) vient de la simple lecture du comportement documenté, et non de la lecture du code source de Glibc.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; }
la source
Si vous savez que chaque numéro de version aura exactement 3 entiers séparés par des points, vous pouvez les analyser (par exemple en utilisant
sscanf(3)
) et les comparer: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 }
la source
Pour vérifier la version dans Swift, vous pouvez utiliser les éléments suivants
switch newVersion.compare(currentversion, options: NSStringCompareOptions.NumericSearch) { case .OrderedDescending: println("NewVersion available ") // Show Alert Here case .OrderedAscending: println("NewVersion Not available ") default: println("default") }
J'espère que cela pourrait être utile.
la source
Voici une fonction récursive qui fonctionne avec le formatage de plusieurs versions de n'importe quelle longueur. Cela fonctionne également pour @ "1.0" et @ "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); } }
Échantillons de test:
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");
la source