Compare versions as strings

后端 未结 4 1869
一整个雨季
一整个雨季 2020-12-16 05:20

Comparing version numbers as strings is not so easy...
\"1.0.0.9\" > \"1.0.0.10\", but it\'s not correct.
The obvious way to do it properly is to parse these strings

相关标签:
4条回答
  • 2020-12-16 05:53

    First the test code:

    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
    

    Implementation:

    #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

    0 讨论(0)
  • 2020-12-16 05:56
    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;
    }
    
    0 讨论(0)
  • 2020-12-16 06:03

    I would create a version class.
    Then it is simple to define the comparison operator for the version class.

    #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";
        }
    }
    
    0 讨论(0)
  • 2020-12-16 06:06

    I don't see what could be more elegant than just parsing -- but please make use of standard library facilities already in place. Assuming you don't need error checking:

    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);
    }
    

    Anything more complicated is going to be harder to maintain and isn't worth your time.

    0 讨论(0)
提交回复
热议问题