美文网首页程序员
版本号大小比较算法

版本号大小比较算法

作者: waylen | 来源:发表于2016-05-21 20:17 被阅读5394次

    版本号之间比较大小,本质上是比较字符串之间的关系。这里给定两个版本号,你一定能迅速地区分出大小:

    0.0.2
    0.0.3
    

    想要让计算机程序分辨她们的关系,可以直接使用strcmp()函数获取返回值,如果你在 iOS 系统下编程,也可以使用 NSString 类提供的- (NSComparisonResult)compare:(NSNumber *)decimalNumber方法。

    但如果版本进化成下面这样,上面所说的 API 一定会产生错误的结果。

    2.7.14.2345
    2.12.8.1234
    

    因为单纯的字符串比较大小的依据是每个字符的 ASCII 码。程序会认为字符7比字符1大,结果就是第一个版本号大于第二个版本号,这是错误的。

    因此在识别之前,有必要了解一下版本号的组成部分,以及每一个数字的意义,这里已 GUN 风格的版本号作为说明。

    版本号大致以下几个部分组成:

    • 主版本号
    • 次版本号
    • 修正版本号
    • 编译版本号

    示例: 3.5.20.9527

    在比较版本号时,正确的做法应该是,主版本号和主版本号比较,次版本号和次版本号比较等等。所以算法的核心应该是分离出版本号的各个组成部分。这个检测算法用 Swift 来做非常简单,只需要利用数组的 lexicographicallyPrecedes 方法即可实现。相关代码可查阅该项目OhMyVersion

    当然 Objective-C 语言里并没有 Array 的这个方法,那我们就自己动手实现一个。以下是一个简单的实现:

    @implementation NSArray (Compare)
    
    - (BOOL)lexicographicallyPrecedesWithOther:(NSArray *)array areInIncreasingOrder:(BOOL (^)(id, id))block
    {
        NSParameterAssert(array);
        NSParameterAssert(block);
        NSUInteger idx = 0;
        
        for (id obj in self) {
            if (idx == array.count) { break; }
            
            if ([obj isEqual:array[idx]]) { ++idx; continue; }
            
            return block(obj, array[idx]);
        }
        
        return self.count > array.count;
    }
    
    @end
    

    下面我也列举了粗暴的 C 语言算法原理:

    /**
     * 比较版本号
     *
     * @param v1 第一个版本号
     * @param v2 第二个版本号
     *
     * @return 如果版本号相等,返回 0,
     *         如果第一个版本号低于第二个,返回 -1,否则返回 1.
     */
    int compareVersion(const char *v1, const char *v2)
    {
        assert(v1);
        assert(v2);
        
        const char *p_v1 = v1;
        const char *p_v2 = v2;
        
        while (*p_v1 && *p_v2) {
            char buf_v1[32] = {0};
            char buf_v2[32] = {0};
            
            char *i_v1 = strchr(p_v1, '.');
            char *i_v2 = strchr(p_v2, '.');
            
            if (!i_v1 || !i_v2) break;
            
            if (i_v1 != p_v1) {
                strncpy(buf_v1, p_v1, i_v1 - p_v1);
                p_v1 = i_v1;
            }
            else
                p_v1++;
            
            if (i_v2 != p_v2) {
                strncpy(buf_v2, p_v2, i_v2 - p_v2);
                p_v2 = i_v2;
            }
            else
                p_v2++;
            
            
            
            int order = atoi(buf_v1) - atoi(buf_v2);
            if (order != 0)
                return order < 0 ? -1 : 1;
        }
        
        double res = atof(p_v1) - atof(p_v2);
        
        if (res < 0) return -1;
        if (res > 0) return 1;
        return 0;
    }
    

    Test case:

    int main(int argc, char *argv[])
    {
        assert(compare_version("2.2.1", "2.2.0") > 0);
        assert(compare_version("2.2.1", "2.1.9") > 0);
        assert(compare_version("2.2.1", "2.2.01") == 0);
        assert(compare_version("2.2.1", "2.2.1") == 0);
        assert(compare_version("2.2", "2.1.1") > 0);
        assert(compare_version("2.2", "2.2.1") < 0);
        assert(compare_version("2.2.3.1", "2.2.3.5") < 0);
        assert(compare_version("2.2.3.1", "2.2.3.0") > 0);
        assert(compare_version("2.2", "2.2.1.4.5") < 0);
        assert(compare_version("2.2.3.4", "2.2.4.4.5") < 0);
        assert(compare_version("2.2.3.4.5.6", "2.2.3.4.5.12") < 0);
        assert(compare_version("2.2.3.4.5.6", "2.2.2.4.5.12") > 0);
        assert(compare_version("3.0.0.1", "3.0.0.0.1") > 0);
        assert(compare_version("3.1", "3.1.") == 0);
        
        puts("test pass.");
    }
    

    相关文章

      网友评论

        本文标题:版本号大小比较算法

        本文链接:https://www.haomeiwen.com/subject/yjlorttx.html