6

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.

hippietrail
  • 15,848
  • 18
  • 99
  • 158
Huang Xu
  • 93
  • 2
  • 8

5 Answers5

5

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

nneonneo
  • 171,345
  • 36
  • 312
  • 383
2

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;
}
Chiel
  • 6,006
  • 2
  • 32
  • 57
1

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.

Tyler
  • 11
  • 4
  • 1
    I think you can't just ignore dots. you have to keep the first dot. otherwise, 2.1.1 will be the same as .2.1.1 – Huang Xu Oct 14 '15 at 21:21
  • Your idea basically is to compare versions as if they were digits of a base-10 number. But your algorithm fails with any number that is higher than 9 (and thus can't be treated correctly as a digit of a base-10 number). For example, I'm using Chrome 45.0.2454.101 right now. This version, with your algorithm, would be considered higher than 45.1.0.0, or even 46.0.0.0. To fix the algorithm you'd have to work in base 2455 (one more than the highest number), that is, you'd have to replace `n1 = n1 * 10;` with `n1 = n1 * 2455;` but to find out this number you'd have to parse both versions first. – Fabio says Reinstate Monica Oct 14 '15 at 21:24
  • And then again, even with my change, how would you compare versions if they had a different number of dots, that is, something like 45.3 vs 46? You'd have to convert 46 to 46.0 first. All in all, it's a lot of work, and not worth it. – Fabio says Reinstate Monica Oct 14 '15 at 21:25
0

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.

sasha.sochka
  • 14,395
  • 10
  • 44
  • 68
-1

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
mkungla
  • 3,390
  • 1
  • 26
  • 37
  • This is buggy. Consider `CompareVersion("2.3") <= CompareVersion("2.2")` and `CompareVersion("2.3") <= CompareVersion("1.4")`. Both expressions are true but should be false. – metal Sep 02 '16 at 16:58