比较c中的版本号

bar*_*kyo 6 c string-comparison version-numbering

我在其他语言中看到了很多关于这个问题的答案,但我试图找到一种方法来比较作为字符串给出的2个版本号.例如

str1 = "141.1.23"
str2 = "141.1.22"
Run Code Online (Sandbox Code Playgroud)

我试图找到一种方法来比较字符串中的整数值,看看哪一个更大.(在这种情况下,str1会更大).我想过使用atoi和strtok的某些时候,但我知道我不能一次标记2个字符串.有什么建议?

Mec*_*cki 12

我真的很想知道为什么人们sscanf在 C 中有如此复杂的解决方案。这是一个非常简单的解决方案,适用于所有用例的 99%:

int compVersions ( const char * version1, const char * version2 ) {
    unsigned major1 = 0, minor1 = 0, bugfix1 = 0;
    unsigned major2 = 0, minor2 = 0, bugfix2 = 0;
    sscanf(version1, "%u.%u.%u", &major1, &minor1, &bugfix1);
    sscanf(version2, "%u.%u.%u", &major2, &minor2, &bugfix2);
    if (major1 < major2) return -1;
    if (major1 > major2) return 1;
    if (minor1 < minor2) return -1;
    if (minor1 > minor2) return 1;
    if (bugfix1 < bugfix2) return -1;
    if (bugfix1 > bugfix2) return 1;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在这里,试一试:https : //ideone.com/bxCjsb


das*_*ght 5

我知道我不能一次标记2个字符串.

幸运的是,您不需要:创建一个接受字符串的函数,并使用strtok_r(使用可重入版本,它更安全)解析三个整数.

strunct version_t {
    int major;
    int minor;
    int build;
};

version_t parse_ver(const char* version_str) {
    version_t res;
    // Use strtok_r to split the string, and atoi to convert tokens to ints
    return res;
}
Run Code Online (Sandbox Code Playgroud)

现在你可以调用parse_ver两次,获得两个version_t值,并将它们并排比较.

PS如果您采用约定来始终将前导零填充到特定长度的数字,即确保您写入"141.1.03"而不是"141.1.3",则可以用字典对数替换整数比较.


小智 5

以下例程比较由真实数字组成的版本号字符串。优点是分隔符无关紧要;例如,它可以与 141.01.03、141:1:3 甚至 141A1P3 配合使用。它还可以处理不匹配的尾部,以便 141.1.3 将出现在 141.1.3.1 之前。

#include <assert.h>
#include <stdlib.h>

int versionCmp( char *pc1, char *pc2)
{
    int result = 0;
    /* loop through each level of the version string */
    while (result == 0) {
        /* extract leading version numbers */
        char* tail1;
        char* tail2;
        unsigned long ver1 = strtoul( pc1, &tail1, 10 );
        unsigned long ver2 = strtoul( pc2, &tail2, 10 );
        /* if numbers differ, then set the result */
        if (ver1 < ver2)
            result = -1;
        else if (ver1 > ver2)
            result = +1;
        else {
            /* if numbers are the same, go to next level */
            pc1 = tail1;
            pc2 = tail2;
            /* if we reach the end of both, then they are identical */
            if (*pc1 == '\0' && *pc2 == '\0')
                break;
            /* if we reach the end of one only, it is the smaller */
            else if (*pc1 == '\0')
                result = -1;
            else if (*pc2 == '\0')
                result = +1;
            /*  not at end ... so far they match so keep going */
            else {
                pc1++;
                pc2++;
            }
        }
    }
    return result;
}

int main( void )
{
    assert(versionCmp("1.2.3" , "1.2.3" ) == 0);
    assert(versionCmp("1.2.3" , "1.2.4" )  < 0);
    assert(versionCmp("1.2.4" , "1.2.3" )  > 0);
    assert(versionCmp("10.2.4", "9.2.3" )  > 0);
    assert(versionCmp("9.2.4",  "10.2.3")  < 0);
    /* Trailing 0 ignored. */
    assert(versionCmp("01", "1") == 0);
    /* Any single space delimiter is OK. */
    assert(versionCmp("1a2", "1b2") == 0);
    return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)

将 s替换strtoulstrcspns 和 a strncmp,您可以使用它来比较非数字版本的“数字”——但分隔符必须是点。例如,141.3A.1 排序在 141.3B 之前。

...
while (result == 0) {
    /* ignore leading zeroes */
    pc1 += strspn( pc1, "0" );
    pc2 += strspn( pc2, "0" );
    /* extract leading version strings */
    int len1 = strcspn( pc1, "." );
    int len2 = strcspn( pc2, "." );
    /* if one is shorter than the other, it is the smaller version */
    result = len1 - len2;
    /* if the same length then compare as strings */
    if (result == 0)
        result = strncmp( pc1, pc2, len1 );
    if (result == 0) {
        pc1 += len1;
        pc2 += len2;
        if (*pc1 == '\0' && *pc == '\0')
            ...
Run Code Online (Sandbox Code Playgroud)