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

2020-02-14 06:01发布

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.

5条回答
Evening l夕情丶
2楼-- · 2020-02-14 06:18

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.

查看更多
祖国的老花朵
3楼-- · 2020-02-14 06:20

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
查看更多
劫难
4楼-- · 2020-02-14 06:22

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楼-- · 2020-02-14 06:23

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.

查看更多
Luminary・发光体
6楼-- · 2020-02-14 06:39

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).

查看更多
登录 后发表回答