2010-05-31 3 views
6

Vergleiche Versionsnummern als Strings ist nicht so einfach ...
"1.0.0.9"> "1.0.0.10", aber es ist nicht korrekt.
Der offensichtliche Weg, es richtig zu machen, ist, diese Zeichenfolgen zu analysieren, zu Zahlen zu konvertieren und als Zahlen zu vergleichen. Gibt es einen anderen Weg, es "eleganter" zu machen? Zum Beispiel, boost :: string_algo ...Versionen als Strings vergleichen

+1

http://stackoverflow.com/a/34484221/1318830 dort beantwortet und fand dann Ihre Frage –

+0

Ich schlage vor, dass Version Klasse statt String erstellen. Sie könnten auch '1.0.0.9 Beta' benötigen. Das ist kein einfacher Ganzzahlvergleich. –

+2

C Version dieser Frage für Interessierte: [Vergleichen Versionsnummern in c] (http://StackOverflow.com/Questions/15057010) – hippietrail

Antwort

23

Ich sehe nicht, was eleganter als nur Parsing sein könnte - aber bitte nutzen Sie die Standard-Bibliothek Einrichtungen bereits vorhanden. Vorausgesetzt, dass Sie nicht die Fehlerüberprüfung benötigen:

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

Alles, was komplizierter sein wird, schwieriger zu pflegen und Ihre Zeit nicht wert.

+2

+1: Ordentliche STL-Nutzung. Tippfehler in 'std :: lexicographic_compare'. – Johnsyweb

+2

Der Algorithmus ist gut. Ich würde vorschlagen, es als 'class Version {Version (std :: string const &); bool operator <(Version const & rhs) const; }; '. So können Sie zum Beispiel ein 'std :: set ' haben. – MSalters

+0

@Johnsyweb: Danke, dass du den Tippfehler aufgehoben hast. @ MSalters: Ich stimme zu. Ich sagte nicht, dass ich das für die Produktion verwende - ich habe gerade den Algorithmus demonstriert, den das OP meiner Meinung nach verwenden sollte. –

6

Ich würde eine Versionsklasse erstellen.
Dann ist es einfach, den Vergleichsoperator für die Versionsklasse zu definieren.

#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

Sie sollten 'std :: vector :: assign' anstelle von 'std :: copy';) Sonst +1 verwenden. –

+0

Nur ein kleiner Vorschlag, um die Klasse operatormäßig zu vervollständigen. Wenn _boost_ verfügbar ist, könnte man von [boost :: less_than_comparable_] (https://theboostcpplibraries.com/boost.operators) ableiten, um 'operator>', 'operator <=' und 'operator> =' automatisch hinzuzufügen welche alle in Form von "operator <" implementiert sind. Nützlich wäre auch "operator ==" und von "boost :: equality_comparable" abzuleiten, um 'operator! =' Zu erhalten. – zett42

+0

@ zett42. Keinen Bedarf. Um die Vergleichsoperatoren hinzuzufügen, müssen Sie nur 'using namespace std :: rel_ops' hinzufügen. [see] (http://www.cplusplus.com/reference/utility/rel_ops/) –

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