【问题标题】:How to parse version number to compare it?如何解析版本号进行比较?
【发布时间】:2013-01-17 07:41:18
【问题描述】:

场景:我有一个简单的应用程序,它检查它的 RSS 提要并查看是否有可用的更新版本。因此,我想检查当前版本是否低于 RSS 提要中的版本。理想情况下很简单:

CURRENTVERSION < updateVersion

问题:版本控制由major.minor.revision.build 组成,我不知道如何将其解析为数字来执行版本检查。

这些是要比较的参数:

#define CURRENTVERSION = 0,2,5,1

从网上下载的版本是"0.2.6.1"(作为字符串)。

检查一个是否小于另一个的最佳方法是什么?

我尝试将其转换为双精度,但值变为 0.2(仅解析第一个 .,忽略其余部分)。

约束:它不能是使用 .NET 库的解决方案,因为应用程序必须在没有 .NET 框架的情况下工作。

(编辑)感谢 Karthik T 的回答,我选择了以下解决方案。

struct Version
{
    Version(string versionStr)
    {
        sscanf(versionStr.c_str(), "%d.%d.%d.%d", &major, &minor, &revision, &build);
    }

    bool operator<(const Version &otherVersion)
    {
        if(major < otherVersion.major)
            return true;
        if(minor < otherVersion.minor)
            return true;
        if(revision < otherVersion.revision)
            return true;
        if(build < otherVersion.build)
            return true;
        return false;
    }

    int major, minor, revision, build;
};

【问题讨论】:

  • 先问一个问题:你为什么将#define版本作为等号,后跟逗号分隔的整数列表,而网页版中的整数列表是点分隔的?我觉得那里没有任何意义。您可以只使用#define CURRENTVERSION "0.2.5.1" 或者更好的const char CURRENTVERSION[] = "0.2.5.1";,因为这里不需要使用宏。
  • @AmadeusHein 您的比较方法不正确。例如,它声称Version("1.0.0.0") 小于Version("0.2.5.1")。在每个if(x &lt; otherVersion.x) return true; 之后应该有一个if(otherVersion.x &lt; x) return false;
  • 请不要将您的解决方案放入您的问题中;而是将其添加为答案。添加一个对另一个答案进行改进的答案是可以的。
  • 您的解决方案有缺陷。您拥有的代码会尝试从 3.1.2.2 更新到 2.2.2.2,因为例如 minor 是 less 。

标签: c++ parsing version-numbering


【解决方案1】:
struct Version{
    Version(std::string versionStr);     //remember to use  versionStr.c_str() if using C functions like sscanf or strtok
    bool operator<(const Version &other); // could and perhaps should be a free function

    int major,minor,revision,build;
};


bool needtoUpdate = Version(CURRENTVERSION)<Version(latestVersion);

请填写定义。

另外,您的#define 是一个错误。你想要它像下面。或者如果可以的话,使用const char *

#define CURRENTVERSION "0.2.5.1"

您可以使用sscanfstrtok 之类的东西在构造函数中进行解析。

【讨论】:

  • 谢谢!这看起来很棒。我对 C++ 很陌生(我敢肯定你认为 :)),你会非常介意显示构造函数解析吗?
  • 当他可以(因此应该)使用 const 变量时,他为什么还要#define呢?
  • 我更愿意把它作为练习留给你 :) 查找“tokenize string C++”或查看cplusplus.com/reference/cstring/strtok
  • 我不知道这是否是最好的方法,但这个应用程序是一个 .NET 依赖应用程序的包装器,并且有一个构建脚本更改 CURRENTVERSION(到 .NET 应用程序的那个)。我认为更改#define 是最简单的。
  • @ArneMertz 主要限制我对问题的更改,const char * 是首选,但在这种情况下,我更喜欢定义,因为我需要在 .cpp 中定义 var 以避免多个定义等。
【解决方案2】:

我建议只使用一个函数,其参数是两个字符串,代表版本号。没有必要使用结构或类来做这么简单的事情。我认为最好保持简单。例如:

#include <stdio.h>
#include <string.h>

/*
 * return 1 if v1 > v2
 * return 0 if v1 = v2
 * return -1 if v1 < v2
 */

int cmpVersion(const char *v1, const char *v2)
{
    int i;
    int oct_v1[4], oct_v2[4];
    sscanf(v1, "%d.%d.%d.%d", &oct_v1[0], &oct_v1[1], &oct_v1[2], &oct_v1[3]);
    sscanf(v2, "%d.%d.%d.%d", &oct_v2[0], &oct_v2[1], &oct_v2[2], &oct_v2[3]);

    for (i = 0; i < 4; i++) {
        if (oct_v1[i] > oct_v2[i])
            return 1;
        else if (oct_v1[i] < oct_v2[i])
            return -1;
    }

    return 0;
}

int main()
{
    printf("%d\n", cmpVersion("0.1.2.3", "0.2.3.4"));
}

【讨论】:

  • 使用结构体的性能开销为 0,甚至可以在对版本向量进行排序的简单情况下提高性能,而不是保存代表版本的字符串向量。此外,“没有必要使用结构或类来做这么简单的事情”只是对类型的整个概念和类型系统的巨大好处不屑一顾。一个简单的例子是不能将不代表版本的字符串传递给需要版本的函数。
【解决方案3】:

如果你有支持C++11的编译器,可以std::tuple让代码更干净:

 struct Version
  {
      Version(std::string versionStr)
      {
          sscanf(versionStr.c_str(), "%d.%d.%d.%d", &major, &minor, &revision, &build);
      }
      VersionTuple ToTuple() const
      {
          return VersionTuple{ major,minor,revision,build };
      }
      int major, minor, revision, build;
  };

  bool operator<(const Version& v1, const Version& v2)
  {
      return v1.ToTuple() < v2.ToTuple();
  }

【讨论】:

  • 什么是VersionTuple?这段代码中好像没有定义。
猜你喜欢
  • 2021-05-06
  • 2023-03-20
  • 2016-07-23
  • 1970-01-01
  • 2011-12-16
相关资源
最近更新 更多