How to compare version numbers in C++ [duplicate]

☆樱花仙子☆ 提交于 2019-12-29 08:52:08

问题


Our professor want us to write a program to compare two version numbers, like 0.1 < 0.2 or 1 < 1.1. Also there are some trick ones like .0.4 < .1. So, my idea is first judge if the number start as a dot, if it does, I add a 0 to it. After that I remove other dots except the first one. Then I convert string to number and compare them. Here's what I do in the first step.

string numb1,numb2;
if(numb1[0]=='.')
{
    numb1 ="0"+ numb1;
}

I do the same thing to the second number. And now I need help to show me how to remove the dots except the first one. Our professor want us to use this specific function: int compareVersions(string ver1, string ver2). If ver1 > ver2: return 1 if ver1 < ver2: return -1 otherwise return 0.

By the way, some of the vision number may very long like 2.3.2.2.3.1.1.5.3.5.6.2 or 1.1.1.1.1.1.1.


回答1:


Here's one approach that should work for numerical version numbers:

  • Split the input strings into pieces using getline(strstream, token, ".")
  • Convert corresponding pieces to numbers using atoi or stol and compare numerically

Basically, treat the version numbers as sequences of numbers separated by . and compare those sequences lexicographically.


Note that a practical, general version number comparison algorithm probably needs to handle extra trickiness such as letter suffixes (e.g. 1.1e, 2.4b24, 3.5rc1), etc. I'm assuming that this is outside the scope of a class exercise, but the approach is similar: split these parts into sequences of numeric and non-numeric parts and compare each part (e.g. 2.4b7 < 2.4b24 because 4, "b", 7 < 4, "b", 24).




回答2:


Since you know numb[1] would equal to '.' you can just use

 numb1.erase(std::remove(numb1.begin() + 2, numb1.end(), '.'), numb1.end());

Which would remove all dots in numb1 after the second character.




回答3:


What you need to do is iterate through the string, ignoring '.' and converting the char representations of numbers into ints. Then compare the two end results.

string numb1 = "4.3.2";
string numb2 = "3.4.5";
int n1 = 0;
int n2 = 0; 

for (int i = 0; i < numb1.length(); i++)
{
    if (numb1[i] != '.')
    {   
        n1 = n1 * 10;
        n2 = n2 * 10;
        n1 += (int(numb1[i]) - '0');
        n2 += (int(numb2[i]) - '0');                
    }

}

That will give you 432 and 345, comparing those would give you which is the higher version.




回答4:


Something like this would work to do the checking and is fairly minimal. It makes use of boost to split the string and then compares the version step by step. It automatically deals with missing leading zeros.

#include <boost/algorithm/string.hpp>
#include <string>
#include <vector>
#include <iostream>

int version_a_newer_than_b(const std::string& a, const std::string& b)
{
    // First, split the string.
    std::vector<std::string> va, vb;
    boost::split(va, a, boost::is_any_of("."));
    boost::split(vb, b, boost::is_any_of("."));

    // Compare the numbers step by step, but only as deep as the version
    // with the least elements allows.
    const int depth = std::min(va.size(), vb.size());
    int ia,ib;
    for (int i=0; i<depth; ++i)
    {
        ia = atoi(va[i].c_str());
        ib = atoi(vb[i].c_str());
        if (ia != ib)
            break;
    }

    // Return the required number.
    if (ia > ib)
        return 1;
    else if (ia < ib)
        return -1;
    else
    {
        // In case of equal versions, assumes that the version
        // with the most elements is the highest version.
        if (va.size() > vb.size())
            return 1;
        else if (va.size() < vb.size())
            return -1;
    }

    // Everything is equal, return 0.
    return 0;
}

int main()
{
    std::string a = "0.1.32.8";
    std::string b = "0.1";

    std::cout << "Is a newer than b: " << version_a_newer_than_b(a, b) << std::endl;

    return 0;
}



回答5:


Following example will demonstrates comparison between following version format: major.minor.revision.build or any shorter version, like only major while it allows you to extend it to fit your needs as of,

"some of the version numbers may be very long like 2.3.2.2.3.1.1.5.3.5.6.2"

Using example bellow, dots in the beginning and end of the version string are taken care of as far .0.4 is considered to be equal to 0.0.4 and .1. is considered to be equal to 0.1.0.

CompareVersion.h

#ifndef COMPAREVERSION_H_
#define COMPAREVERSION_H_
#include <cstdio>
#include <string>
#include <iostream>
using namespace std;
struct CompareVersion {
public:
    int maj;
    int min;
    int rev;
    int build;
    CompareVersion(std::string);
    bool operator < (const CompareVersion&);
    bool operator <= (const CompareVersion&);
    bool operator == (const CompareVersion&);
    friend std::ostream& operator << (std::ostream& stream, const CompareVersion& ver) {
        stream << ver.maj;
        stream << '.';
        stream << ver.min;
        stream << '.';
        stream << ver.rev;
        stream << '.';
        stream << ver.build;
        return stream;
    };
    void reset();
};
#endif /* COMPAREVERSION_H_ */

CompareVersion.cpp

#include "CompareVersion.h"
CompareVersion::CompareVersion(std::string version) 
{
    reset();
    if (version.compare(0,1,".") == 0)
        version = "0"+version;
    if (version.compare(version.size()-1,1,".") == 0)
        version.append("0");
    sscanf(version.c_str(), "%d.%d.%d.%d", &maj, &min, &rev, &build);
    if (maj <= 0) maj = 0;
    if (min <= 0) min = 0;
    if (rev <= 0) rev = 0;
    if (build <= 0) build = 0;
}
bool CompareVersion::operator < (const CompareVersion& other)
{
    if (maj < other.maj) return true;
    if (min < other.min) return true;
    if (rev < other.rev) return true;
    if (build < other.build) return true;

    return false;
}
bool CompareVersion::operator <= (const CompareVersion& other)
{
    if (maj >= other.maj) return true;
    if (min >= other.min) return true;
    if (rev >= other.rev) return true;
    if (build >= other.build) return true;

    return false;
}
bool CompareVersion::operator == (const CompareVersion& other)
{
    return maj == other.maj
    && min == other.min
    && rev == other.rev
    && build == other.build;
}
void CompareVersion::reset()
{
    maj = 0;
    min = 0;
    rev = 0;
    build = 0;
}

main.cpp

#include <iostream>
#include "CompareVersion.h"
using namespace std;
int main() 
{
    if((CompareVersion("1.2.3.4") == CompareVersion("1.2.3.4")) == true)
    cout << "Version 1.2.3.4 and version 1.2.3.4 are equal" << endl;

    if((CompareVersion("1.2.3.3") < CompareVersion("1.2.3.4")) == true)
    cout << "Version 1.2.3.3 is smaller than 1.2.3.4. " << endl;

    if((CompareVersion("1.2.3.4") < CompareVersion("1.2.3.4")) == true)
    cout << "You won't see that. " << endl;

    if((CompareVersion("1.2.3.4") <= CompareVersion("1.2.3.4")) == true)
    cout << "Version 1.2.3.4 is smaller or equal to 1.2.3.4" << endl;
    if((CompareVersion("1") <= CompareVersion("1.0.0.1")) == true)
    cout << "Version 1 is smaller or equal to 1.0.0.1" << endl;
    /* THE DOTS */
    if((CompareVersion(".0.4") == CompareVersion("0.0.4")) == true)
    cout << "Version .0.4 and version 0.0.4 are equal" << endl;
    if((CompareVersion(".1.") == CompareVersion("0.1.0")) == true)
    cout << "Version .1. and version 0.1.0 are equal" << endl;
    if((CompareVersion("1") == CompareVersion("1.0.0.0")) == true)
    cout << "Version 1 and version 1.0.0.0 are equal" << endl;
    return 0;
}

Output

Version 1.2.3.4 and version 1.2.3.4 are equal
Version 1.2.3.3 is smaller than 1.2.3.4. 
Version 1.2.3.4 is smaller or equal to 1.2.3.4
Version 1 is smaller or equal to 1.0.0.1
Version .0.4 and version 0.0.4 are equal
Version .1. and version 0.1.0 are equal
Version 1 and version 1.0.0.0 are equal


来源:https://stackoverflow.com/questions/33135019/how-to-compare-version-numbers-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!