2010-05-31 16 views
6

Comparar números de versión como cadenas no es tan fácil ...
"1.0.0.9"> "1.0.0.10", pero no es correcto.
La forma obvia de hacerlo correctamente es analizar estas cadenas, convertir a números y compararlos como números. ¿Hay alguna otra manera de hacerlo más "elegantemente"? Por ejemplo, boost :: string_algo ...Comparar versiones como cadenas

+1

http://stackoverflow.com/a/34484221/1318830 respondida allí y luego encontró su pregunta –

+0

Sugiero que crean la clase en lugar de la versión de cadena. es posible que también necesites '1.0.0.9 beta'. eso no es una simple comparación de enteros. –

+2

versión C de esta cuestión para los interesados: [números de versión que comparan en c] (http://stackoverflow.com/questions/15057010) – hippietrail

Respuesta

23

No veo lo que podría ser más elegante que el análisis, pero por favor hacer uso de las instalaciones de biblioteca estándar ya instaladas. Suponiendo que no es necesario la comprobación de errores:

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

algo más complicado va a ser más difícil de mantener y no es digno de su tiempo.

+2

1: Uso STL Neat. Typo en 'std :: lexicographical_compare'. – Johnsyweb

+2

El algoritmo es bueno. Sugiero envolverlo como una 'clase Version {Version (std :: string const &); bool operator <(Version const & rhs) const; }; '. Esto le permite tener un 'std :: set ' por ejemplo. – MSalters

+0

@Johnsyweb: Gracias por retomar el error tipográfico. @MSalters: estoy de acuerdo. No estaba diciendo usar esto para producción, solo estaba demostrando el algoritmo que creo que debería usar OP. –

6

me gustaría crear una clase de versión.
Luego es simple definir el operador de comparación para la clase de versión.

#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

Debe usar 'std :: vector :: assign' en lugar de' std :: copy';) De lo contrario, +1. –

+0

Solo una pequeña sugerencia para hacer que la clase sea más completa, en cuanto al operador. Si _boost_ está disponible, uno podría [derivar de 'boost :: less_than_comparable'] (https://theboostcpplibraries.com/boost.operators) para agregar automáticamente' operator> ',' operator <= ', y' operator> = ' que están todos implementados en términos de 'operator <'. También sería útil 'operator ==' y derivar de 'boost :: equality_comparable' para proporcionar' operator! = '. – zett42

+0

@ zett42. No hay necesidad de eso. Para agregar operadores de comparación, todo lo que necesita hacer es agregar 'using namespace std :: rel_ops'. [ver] (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; 
} 
Cuestiones relacionadas