比较版本号

时间:2011-03-01 20:54:04

标签: cocoa comparison versioning

前段时间,我读到可以使用以下代码片段来比较版本号:

NSString *vesrion_1 = @"1.2.1";
NSString *version_2 = @"1.2.0";

if ([version_1 compare:version_2 options:NSNumericSearch] == NSOrderedAscending) {
...
}

这似乎工作正常,但是一个用户遇到问题,这是由于看似不正确的版本号比较。

我的问题是,在所有情况下使用此技术比较版本号是否安全?上述比较是否有可能在不同的机器上产生不同的结果?

8 个答案:

答案 0 :(得分:4)

我在GitHub上开发了一个非常轻巧且易于使用的VersionComparator - 不像其他一些解决方案那样功能丰富,但很容易上手和使用。

BOOL greater = [VersionComparator isVersion:@"2.0.0" greaterThanVersion:@"1.1.0"];

它简单地比较了从主要到构建的数字 - 如果2大于1那么就没有必要进一步比较。

它的目标是尽可能简单地提供前端代码(如上例所示),也不提供具有大量支持代码的类。通常情况下,这就是所需要的。

答案 1 :(得分:3)

我不知道内置会做什么,但我听说Sparkle framework有一个版本比较器。

快速浏览源代码显示SUStandardVersionComparator对象似乎负责它。它符合<SUVersionComparison> protocol,这意味着您可以像这样使用它:

NSString *versionA = @"1.2.1";
NSString *versionB = @"1.2.0";
id <SUVersionComparison> comparator = [SUStandardVersionComparator defaultComparator];
NSInteger result = [comparator compareVersion:versionA toVersion:versionB];
if (result == NSOrderedSame) {
  //versionA == versionB
} else if (result == NSOrderedAscending) {
  //versionA < versionB
} else {
  //versionA > versionB
}

(注意:代码未经测试并在浏览器中输入。警告执行者

答案 2 :(得分:3)

NSNumericSearch应该完全按照您的意愿行事。它处理您期望从版本号中获得的所有情况。对于之前的项目,我为此写了一堆测试用例:

+ (NSComparisonResult)compareBundleVersion:(NSString *)a withBundleVersion:(NSString *)b
{
    return [a compare:b options:NSNumericSearch];
}

STAssertEquals(NSOrderedSame, [self compareBundleVersion:@"1" withBundleVersion:@"1"], nil);
STAssertEquals(NSOrderedSame, [self compareBundleVersion:@"1.0" withBundleVersion:@"1.0"], nil);
STAssertEquals(NSOrderedSame, [self compareBundleVersion:@"1.1.12" withBundleVersion:@"1.1.12"], nil);

STAssertEquals(NSOrderedAscending, [self compareBundleVersion:@"1" withBundleVersion:@"2"], nil);
STAssertEquals(NSOrderedAscending, [self compareBundleVersion:@"1" withBundleVersion:@"1.1"], nil);
STAssertEquals(NSOrderedAscending, [self compareBundleVersion:@"1.0" withBundleVersion:@"1.1"], nil);
STAssertEquals(NSOrderedAscending, [self compareBundleVersion:@"1.1.12" withBundleVersion:@"1.1.13"], nil);
STAssertEquals(NSOrderedAscending, [self compareBundleVersion:@"1.1.12" withBundleVersion:@"1.2.1"], nil);

STAssertEquals(NSOrderedDescending, [self compareBundleVersion:@"1.1" withBundleVersion:@"1"], nil);
STAssertEquals(NSOrderedDescending, [self compareBundleVersion:@"1.1" withBundleVersion:@"1.0"], nil);
STAssertEquals(NSOrderedDescending, [self compareBundleVersion:@"1.1.13" withBundleVersion:@"1.1.12"], nil);
STAssertEquals(NSOrderedDescending, [self compareBundleVersion:@"1.2.1" withBundleVersion:@"1.1.12"], nil);

我还用另一张海报提到的先前案例对此进行了测试:

STAssertEquals(NSOrderedDescending, [self compareBundleVersion:@"1.30" withBundleVersion:@"1.3"], nil);
STAssertEquals(NSOrderedDescending, [self compareBundleVersion:@"1.19" withBundleVersion:@"1.3"], nil);

一切都如你期望的那样过去。

答案 3 :(得分:2)

我会说不,这不安全。版本号不是真正的数字,而是数字的层次结构。例如考虑三个版本号:

1.19
1.3
1.30

数字比较会使1.19小于1.3和1.30。它也会说1.3和1.30相等。如果上面是版本号,那几乎肯定不是你想要的。

还存在本地化 * 的问题。在法语中,上面甚至不会解析为数字。

将版本号视为它们是一个独立整数的层次结构,这样做要好得多。您可以使用-componentsSeparatedByString:

轻松删除它们

* 有点讽刺的是,我的浏览器将本地化的英国英语拼写标记为不正确。

答案 4 :(得分:1)

我喜欢迈克(代码较少)的答案,但即使有关于NSNumericSearch的比较选项的问题,这也应该有效。

- (NSComparisonResult)compareVersion:(NSString *)versionA to:(NSString *)versionB
{
   NSArray *versionAComp = [versionA componentsSeparatedByString:@"."];
   NSArray *versionBComp = [versionB componentsSeparatedByString:@"."];

   __block NSComparisonResult result = NSOrderedSame;

   [versionAComp enumerateObjectsUsingBlock:
   ^(NSString *obj, NSUInteger idx, BOOL *stop)
   {
        // handle abbreviated versions.
        if (idx > versionBComp.count -1)
        {
            *stop = YES;
            return;
        }

        NSInteger verAInt = [versionAComp[idx] integerValue];
        NSInteger verBInt = [versionBComp[idx] integerValue];

        if (verAInt != verBInt)
        {
            if (verAInt < verBInt)
                result = NSOrderedAscending;
            else
                result = NSOrderedDescending;

            *stop = YES;
            return;
        }
    }];
   return result; 
}

答案 5 :(得分:0)

在Java中,您可以使用以下代码段来比较版本。如果一个版本号比另一个版本号短,我们用零标准化它。

import java.util.Arrays;
import java.util.Comparator;

public class FreePlay {

    static String[] versions = {"1.5.3.2", "2.3.4", "1.0.3.4", "10.10.1.1", "1.0.2.5", "2.3.4"};
    /**
     * @param args
     */
    public static void main(String[] args) {
        System.out.println("Unsorted versions");
        for (String s: versions) {
            System.out.print("'" + s + "', ");
        }

        System.out.println("\nSorted versions");

        Arrays.sort(versions, new Comparator<String>() {

            @Override
            public int compare(String o1, String o2) {
                String[] firstVersions = o1.split("\\.");
                String[] secondVersions = o2.split("\\.");
                int length = Math.max(firstVersions.length, secondVersions.length);
                for(int i = 0; i < length; i++) {
                    // normalize the length. If one part is short, we normalize it with zero
                    int firstVersion = i < firstVersions.length ? Integer.parseInt(firstVersions[i]) : 0;
                    int secondVersion = i < secondVersions.length ? Integer.parseInt(secondVersions[i]) : 0;
                    if(firstVersion < secondVersion)
                        return -1;
                    if(firstVersion > secondVersion)
                        return 1;
                }
                return 0;
            }});

        for (String s: versions) {
            System.out.print("'" + s + "', ");
        }
    }

}

答案 6 :(得分:0)

使用NSNumericSearch在大多数情况下都有效,但在版本格式不同时会失败;

e.g。比较时

[self compareBundleVersion:@"1.1.12" withBundleVersion:@"1.2"];

它将返回NSOrderedDescending,而它应返回NSOrderedAscending。

请查看我的NSString类别compareToVersion,它可以很好地处理这个问题;

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

还有一些助手;

[@"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"];

查看; https://github.com/stijnster/NSString-compareToVersion

答案 7 :(得分:-1)

来自Apple的文档:

if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
    // Load resources for iOS 6.1 or earlier
} 
else {
    // Load resources for iOS 7 or later
}