我正在编写一个接收带有项目和版本号的数据的应用程序。数字格式为“1.0.1”或“1.2.5”。如何比较这些版本号?我认为他们必须先格式化为字符串,不是吗?我有什么选择来确定“1.2.5”在“1.0.1”之后?
答案 0 :(得分:225)
这是比较版本的最简单方法,请记住“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
}
答案 1 :(得分:16)
我将添加我的方法,该方法将严格的数字版本(没有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;
}
答案 2 :(得分:11)
这是对Nathan de Vries解决问题的扩展,以解决1&lt; 1.0&lt; 1.0.0等。
首先,我们可以在NSString
类别的版本字符串上解决额外的&#34; .0&#34;&#34;
@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&#39;
NSString* requiredVersion = @"1.2.0";
NSString* actualVersion = @"1.1.5";
requiredVersion = [requiredVersion shortenedVersionNumberString]; // now 1.2
actualVersion = [actualVersion shortenedVersionNumberString]; // still 1.1.5
现在我们仍然可以使用Nathan de Vries提出的非常简单的方法:
if ([requiredVersion compare:actualVersion options:NSNumericSearch] == NSOrderedDescending) {
// actualVersion is lower than the requiredVersion
}
答案 3 :(得分:7)
Sparkle(MacOS最受欢迎的软件更新框架)有一个SUStandardVersionComparator类来执行此操作,并且还考虑了内部版本号和beta标记。即它正确地比较了1.0.5 > 1.0.5b7
或2.0 (2345) > 2.0 (2100)
。代码只使用Foundation,因此在iOS上也可以正常工作。
答案 4 :(得分:6)
查看我的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"];
答案 5 :(得分:6)
我自己制作,使用分类..
<强>来源.. 强>
@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;
}
答案 6 :(得分: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")
}
答案 7 :(得分: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
注意alpha有效,但你必须非常小心。一旦你在某个时候去了alpha,你就不能通过改变它背后的任何其他次要数字来扩展它。
<强>代码:强>
- (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;
}
答案 8 :(得分:3)
我的iOS库AppUpdateTracker包含NSString category来执行此类比较。 (实施基于DonnaLea's answer。)
用法如下:
[@"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);
}];
答案 9 :(得分:2)
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")
}
答案 10 :(得分: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
}
答案 11 :(得分:0)
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;
}
答案 12 :(得分:0)
要检查swift中的版本,您可以使用以下
switch newVersion.compare(currentversion, options: NSStringCompareOptions.NumericSearch) {
case .OrderedDescending:
println("NewVersion available ")
// Show Alert Here
case .OrderedAscending:
println("NewVersion Not available ")
default:
println("default")
}
希望它可能会有所帮助。
答案 13 :(得分: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");
答案 14 :(得分:0)
基于@nathan-de-vries 的answer,我写了SemanticVersion.swift来比较Semantic Version。
1.2
< 1.2.0-alpha
< 1.2.0-beta
< 1.2.0
< 1.2.0+build
< 1.2.0.0
< 1.2.99
< 1.11.0
public struct SemanticVersion: ExpressibleByStringLiteral, ExpressibleByIntegerLiteral, ExpressibleByFloatLiteral {
public var stringLiteral: String
public init(stringLiteral literal: String) {
stringLiteral = literal
}
public init(integerLiteral literal: Int) {
stringLiteral = String(literal)
}
public init(floatLiteral literal: Double) {
stringLiteral = String(literal)
}
}
extension SemanticVersion: Comparable {
private var prepared: String {
return stringLiteral.replacingOccurrences(of: "-", with: "\0") + "\n"
}
public static func < (a: SemanticVersion, b: SemanticVersion) -> Bool {
return a.prepared.compare(b.prepared, options: .numeric) == .orderedAscending
}
}
// MARK: EXTENSION
public extension String {
var semanticVersion: SemanticVersion {
return SemanticVersion(stringLiteral: self)
}
}
public extension Int {
var semanticVersion: SemanticVersion {
return SemanticVersion(integerLiteral: self)
}
}
public extension Double {
var semanticVersion: SemanticVersion {
return SemanticVersion(floatLiteral: self)
}
}
XCTAssertTrue(UIDevice.current.systemVersion.semanticVersion >= 14.0)
XCTAssertTrue(2.semanticVersion < "2.0-a")
XCTAssertTrue("2.0-a".semanticVersion < "2.0-b")
XCTAssertTrue("2.0-b".semanticVersion < 2.0)
XCTAssertTrue(2.0.semanticVersion < "2.0+a")
XCTAssertTrue("2.0+a".semanticVersion < "2.0+b")
XCTAssertTrue("2.0+b".semanticVersion < "2.0.0")
XCTAssertTrue("2.0.0".semanticVersion < 2.1)
XCTAssertTrue(2.1.semanticVersion < 2.99)
XCTAssertTrue(2.99.semanticVersion < 11.0)