7

将版本号作为字符串进行比较并不是那么容易......
“1.0.0.9”>“1.0.0.10”,但它不正确。
正确执行此操作的明显方法是解析这些字符串,转换为数字并作为数字进行比较。还有另一种方法可以更“优雅”地做到这一点吗?例如,boost::string_algo...

4

5 回答 5

25

我看不出有什么比解析更优雅的了——但利用已经到位的标准库设施。假设您不需要错误检查:

void Parse(int result[4], const std::string& input)
{
    std::istringstream parser(input);
    parser >> result[0];
    for(int idx = 1; idx < 4; idx++)
    {
        parser.get(); //Skip period
        parser >> result[idx];
    }
}

bool LessThanVersion(const std::string& a,const std::string& b)
{
    int parsedA[4], parsedB[4];
    Parse(parsedA, a);
    Parse(parsedB, b);
    return std::lexicographical_compare(parsedA, parsedA + 4, parsedB, parsedB + 4);
}

任何更复杂的东西都将更难维护,不值得你花时间。

于 2010-05-31T05:25:47.083 回答
7

我会创建一个版本类。
然后为版本类定义比较运算符就很简单了。

#include <iostream>
#include <sstream>
#include <vector>
#include <iterator>

class Version
{
    // An internal utility structure just used to make the std::copy in the constructor easy to write.
    struct VersionDigit
    {
        int value;
        operator int() const {return value;}
    };
    friend std::istream& operator>>(std::istream& str, Version::VersionDigit& digit);
    public:
        Version(std::string const& versionStr)
        {
            // To Make processing easier in VersionDigit prepend a '.'
            std::stringstream   versionStream(std::string(".") + versionStr);

            // Copy all parts of the version number into the version Info vector.
            std::copy(  std::istream_iterator<VersionDigit>(versionStream),
                        std::istream_iterator<VersionDigit>(),
                        std::back_inserter(versionInfo)
                     );
        }

        // Test if two version numbers are the same. 
        bool operator<(Version const& rhs) const
        {
            return std::lexicographical_compare(versionInfo.begin(), versionInfo.end(), rhs.versionInfo.begin(), rhs.versionInfo.end());
        }

    private:
        std::vector<int>    versionInfo;
};

// Read a single digit from the version. 
std::istream& operator>>(std::istream& str, Version::VersionDigit& digit)
{
    str.get();
    str >> digit.value;
    return str;
}


int main()
{
    Version     v1("10.0.0.9");
    Version     v2("10.0.0.10");

    if (v1 < v2)
    {
        std::cout << "Version 1 Smaller\n";
    }
    else
    {
        std::cout << "Fail\n";
    }
}
于 2010-05-31T07:04:18.390 回答
1

首先是测试代码:

int main()
{
    std::cout << ! ( Version("1.2")   >  Version("1.3") );
    std::cout <<   ( Version("1.2")   <  Version("1.2.3") );
    std::cout <<   ( Version("1.2")   >= Version("1") );
    std::cout << ! ( Version("1")     <= Version("0.9") );
    std::cout << ! ( Version("1.2.3") == Version("1.2.4") );
    std::cout <<   ( Version("1.2.3") == Version("1.2.3") );
}
// output is 111111

执行:

#include <string>
#include <iostream>

// Method to compare two version strings
//   v1 <  v2  -> -1
//   v1 == v2  ->  0
//   v1 >  v2  -> +1
int version_compare(std::string v1, std::string v2)
{
    size_t i=0, j=0;
    while( i < v1.length() || j < v2.length() )
    {
        int acc1=0, acc2=0;

        while (i < v1.length() && v1[i] != '.') {  acc1 = acc1 * 10 + (v1[i] - '0');  i++;  }
        while (j < v2.length() && v2[j] != '.') {  acc2 = acc2 * 10 + (v2[j] - '0');  j++;  }

        if (acc1 < acc2)  return -1;
        if (acc1 > acc2)  return +1;

        ++i;
        ++j;
    }
    return 0;
}

struct Version
{
    std::string version_string;
    Version( std::string v ) : version_string(v)
    { }
};

bool operator <  (Version u, Version v) {  return version_compare(u.version_string, v.version_string) == -1;  }
bool operator >  (Version u, Version v) {  return version_compare(u.version_string, v.version_string) == +1;  }
bool operator <= (Version u, Version v) {  return version_compare(u.version_string, v.version_string) != +1;  }
bool operator >= (Version u, Version v) {  return version_compare(u.version_string, v.version_string) != -1;  }
bool operator == (Version u, Version v) {  return version_compare(u.version_string, v.version_string) ==  0;  }

https://coliru.stacked-crooked.com/a/7c74ad2cc4dca888

于 2019-01-07T01:11:55.517 回答
1

这是一个干净、紧凑的 C++20 解决方案,使用新的spaceship operator <=>和 Boost 的字符串拆分算法。

这将版本字符串构造并保存为数字向量 - 可用于进一步处理,或者可以作为临时处理。这也处理不同长度的版本字符串,并接受多个分隔符。

spaceship 运算符允许我们在单个函数定义中为 和<运算符提供结果(尽管必须单独定义相等性)。>==

#include <compare>
#include <boost/algorithm/string.hpp>

struct version {
  std::vector<size_t> data;

  version() {};
  version(std::string_view from_string) {
    /// Construct from a string
    std::vector<std::string> data_str;
    boost::split(data_str, from_string, boost::is_any_of("._-"), boost::token_compress_on);
    for(auto const &it : data_str) {
      data.emplace_back(std::stol(it));
    }
  };

  std::strong_ordering operator<=>(version const& rhs) const noexcept {
    /// Three-way comparison operator
    size_t const fields = std::min(data.size(), rhs.data.size());

    // first compare all common fields
    for(size_t i = 0; i != fields; ++i) {
      if(data[i] == rhs.data[i]) continue;
      else if(data[i] < rhs.data[i]) return std::strong_ordering::less;
      else return std::strong_ordering::greater;
    }

    // if we're here, all common fields are equal - check for extra fields
    if(data.size() == rhs.data.size()) return std::strong_ordering::equal; // no extra fields, so both versions equal
    else if(data.size() > rhs.data.size()) return std::strong_ordering::greater; // lhs has more fields - we assume it to be greater
    else return std::strong_ordering::less; // rhs has more fields - we assume it to be greater
  }

  bool operator==(version const& rhs) const noexcept {
    return std::is_eq(*this <=> rhs);
  }
};

示例用法:

  std::cout << (version{"1.2.3.4"} <  version{"1.2.3.5"}) << std::endl; // true
  std::cout << (version{"1.2.3.4"} >  version{"1.2.3.5"}) << std::endl; // false
  std::cout << (version{"1.2.3.4"} == version{"1.2.3.5"}) << std::endl; // false
  std::cout << (version{"1.2.3.4"} >  version{"1.2.3"})   << std::endl; // true
  std::cout << (version{"1.2.3.4"} <  version{"1.2.3.4.5"}) << std::endl; // true
于 2021-11-24T00:30:28.837 回答
-1
int VersionParser(char* version1, char* version2) {

    int a1,b1, ret; 
    int a = strlen(version1); 
    int b = strlen(version2);
    if (b>a) a=b;
    for (int i=0;i<a;i++) {
            a1 += version1[i];
            b1 += version2[i];
    }
    if (b1>a1) ret = 1 ; // second version is fresher
    else if (b1==a1) ret=-1; // versions is equal
    else ret = 0; // first version is fresher
    return ret;
}
于 2011-06-24T08:30:00.680 回答