Я пишу приложение, которое получает данные с элементами и номерами версий. Числа имеют формат «1.0.1» или «1.2.5». Как я могу сравнить эти номера версий? Я думаю, их нужно сначала отформатировать как строку, не так ли? Какие параметры мне нужны, чтобы определить, что «1.2.5» следует после «1.0.1»?
objective-c
comparison
млечо
источник
источник
Ответы:
Это самый простой способ сравнить версии, помните, что «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 }
источник
componentsSeparatedByString
подход). Вы можете проверить это сами с помощью@"1.8"
vs@"1.7.2.3.55"
и увидеть, что 1.8 выходит вперед.Я добавлю свой метод, который сравнивает строго числовые версии (без a, b, RC и т. Д.) С любым количеством компонентов.
+ (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; }
источник
Это расширение ответа Натана де Фриза на решение проблемы 1 <1.0 <1.0.0 и т. Д.
Во-первых, мы можем решить проблему лишних ".0" в строке нашей версии с помощью
NSString
категории:@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 }
источник
Сделал сам, использую Категория ..
Источник..
@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; }
источник
Sparkle (самая популярная платформа обновления программного обеспечения для MacOS) имеет класс SUStandardVersionComparator, который делает это, а также принимает во внимание номера сборок и бета-маркеры. Т.е. он правильно сравнивает
1.0.5 > 1.0.5b7
или2.0 (2345) > 2.0 (2100)
. В коде используется только Foundation, поэтому он должен работать и на iOS.источник
Посмотрите мою категорию NSString, в которой реализована простая проверка версии на github; 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"];
источник
Версия 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") }
Версия 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") }
источник
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") }
источник
Я думал, что просто поделюсь функцией, которую я собрал для этого. Это совсем не идеально. Пожалуйста, посмотрите, что примеры и результаты. Но если вы проверяете свои собственные номера версий (что я должен делать для управления такими вещами, как миграция базы данных), это может немного помочь.
(также, конечно, удалите операторы журнала в методе. они нужны, чтобы помочь вам увидеть, что он делает, и все)
Тесты:
[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; }
источник
Моя библиотека 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); }];
источник
Glibc имеет функцию
strverscmp
иversionsort
... к сожалению, не переносится на iPhone, но вы можете довольно легко написать свою собственную. Эта (непроверенная) повторная реализация происходит из простого чтения документированного поведения, а не из чтения исходного кода 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; }
источник
Если вы знаете, что каждый номер версии будет иметь ровно 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 }
источник
Чтобы быстро проверить версию, вы можете использовать следующие
switch newVersion.compare(currentversion, options: NSStringCompareOptions.NumericSearch) { case .OrderedDescending: println("NewVersion available ") // Show Alert Here case .OrderedAscending: println("NewVersion Not available ") default: println("default") }
Надеюсь, это может быть полезно.
источник
Вот рекурсивная функция, которая работает с форматированием нескольких версий любой длины. Это также работает для @ "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");
источник