views:

163

answers:

6

I would like to determine if one version number is greater than another. The version number could be any of the following:

4

4.2

4.22.2

4.2.2.233

...as the version number is beyond my control, so I couldn't say how many dots could actually exist in the number.

Since the number is not really a real number, I can't simply say,

Is 4.7 > 4.2.2

How can I go about converting a number, such as 4.2.2 into a real number that could be checked against another version number?

I would preferably like a ColdFusion solution, but the basic concept would also be fine.

A: 

Parse each number separately and compare them iteratively.

if (majorVersion > 4 &&
    minorVersion > 2 &&
    revision > 2)
{
    // do something useful
}

// fail here

That's obviously not CF code, but you get the idea.

Chris
Actually, it is :D That's perfectly valid CFScript (CF8+ or BD/Railo) right there. :)
Shawn Grigson
A: 

You can split the string containing the version by periods, then start at the first index and compare down until one is greater than the other (or if they are equal, one contains a value the other does not).

I'm afraid I've never written in coldfusion but that would be the basic logic I'd follow.

This is a rough unoptimized example:

bool IsGreater(string one, string two)
{
  int count;
  string[] v1;
  string[] v2;

  v1 = one.Split(".");
  v2 = two.Split(".");

  count = (one.Length > two.Length) ? one.Length : two.Length;

  for (int x=0;x<count;x++)
  {
     if (Convert.ToInt32(v1[x]) < Convert.ToInt32(v2[x]))
        return false;
     else if (Convert.ToInt32(v1[x]) > Convert.ToInt32(v2[x])
        return true;
  } // If they are the same it'll go to the next block.

  // If you're here, they both were equal for the shortest version's digit count.
  if (v1.Length > v2.Length)
     return true; // The first one has additional subversions so it's greater.
}
NebuSoft
+1  A: 

A version number is basically a period delimited array of numbers, so you can parse both versions into number arrays, and then compare each element in the first array to the corresponding element in the second array.

To get the array, do:

<cfset theArrayofNumbers = listToArray(yourVersionString, ".")>

and then you can do your comparisons.

jball
A: 

There is no general way to convert multiple-part version numbers into real numbers, if there is no restriction on the size of each part (e.g. is 4.702.0 > 4.7.2?).

Normally you would define a custom comparison function by creating a sequence or array of version-number parts or components, so 4.7.2 is represented as [4, 7, 2] and 4.702.0 is [4, 702, 0]. Then you compare each element of the two arrays until they don't match:

left = [4, 7, 2]
right = [4, 702, 0]

# check index 0
# left[0] == 4, right[0] == 4
left[0] == right[0]
# equal so far

# check index 1
# left[1] == 7, right[1] == 702
left[1] < right[1]
# so left < right

I don't know about ColdFusion, but in some languages you can do a direct comparison with arrays or sequences. For example, in Python:

>>> left = [4, 7, 2]
>>> right = [4, 702, 0]
>>> left < right
True
Paul Stephenson
+4  A: 

This is ripped from the plugin update code in Mango Blog, and updated a little bit. It should do exactly what you want. It returns 1 when argument 1 is greater, -1 when argument 2 is greater, and 0 when they are exact matches. (Note that 4.0.1 will be an exact match to 4.0.1.0)

It uses the CF list functions, instead of arrays, so you might see a small performance increase if you switched to arrays instead... but hey, it works!

function versionCompare( version1, version2 ){
    var len1 = listLen(arguments.version1, '.');
    var len2 = listLen(arguments.version2, '.');
    var i = 0;
    var piece1 = '';
    var piece2 = '';

    if (len1 gt len2){
        arguments.version2 = arguments.version2 & repeatString('.0', len1-len2);
    }else if (len2 gt len1){
        arguments.version1 = arguments.version1 & repeatString('.0', len2-len1);
    }

    for (i=1; i lte listLen(arguments.version1, '.'); i=i+1){
        piece1 = listGetAt(arguments.version1, i, '.');
        piece2 = listGetAt(arguments.version2, i, '.');

        if (piece1 neq piece2){
            if (piece1 gt piece2){
                return 1;
            }else{
                return -1;
            }
        }
    }

    //equal
    return 0;
}

Running your example test:

<cfoutput>#versionCompare('4.7', '4.2.2')#</cfoutput>

prints:

1

Adam Tuttle
+2  A: 

If version 4 actually means 4.0.0, and version 4.2 actually means 4.2.0, you could easily convert the version to a simple integer.

suppose that every part of the version is between 0 and 99, then you could calculate an 'integer version' from X.Y.Z like this:

Version = X*100*100 + Y*100 + Z

If the ranges are bigger or smaller you could use factors higher or lower than 100.

Comparing the version then becomes easy.

Patrick
In general this isn't a bad idea, but he did specifically say, "the version number is beyond my control" which means the version number could be 2.454359043859043.6, which your approach would fail at.
Adam Tuttle