Compare Two Version Strings in PHP

Compare two version strings in PHP

From the PHP interactive prompt using the version_compare function, built in to PHP since 4.1:

php > print_r(version_compare("2.5.1",  "2.5.2")); // expect -1
-1
php > print_r(version_compare("2.5.2", "2.5.2")); // expect 0
0
php > print_r(version_compare("2.5.5", "2.5.2")); // expect 1
1
php > print_r(version_compare("2.5.11", "2.5.2")); // expect 1
1

It seems PHP already works as you expect. If you are encountering different behavior, perhaps you should specify this.

PHP: version_compare() returns -1 when comparing 5.2 and 5.2.0?

The documentation says it compares 'two "PHP-standardized" version number strings'.

You're comparing one PHP-standardized version number string with one non-PHP-standardized version number string.

How to compare version #'s inside a string?

I think you want to consider working with a regex to parse out the "number" part of the version numbers - "10.1.0.a.1" and "9.7.0". After that, you can split by '.' to get two "version arrays".

With the version arrays, you pop elements off them until you find a higher number. Whichever array it came from is the higher version number. If either array runs out, it's a lesser version number (unless all the remaining elements are "0" or "a" or whatever semantics you use to say "base version", e.g., "10.0.0.a.0" == "10.0"). If both run out at the same time, then they're equal.

Comparing PHP version numbers using Bash?

Here's how to compare versions.

using sort -V:

function version_gt() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; }

example usage:

first_version=5.100.2
second_version=5.1.2
if version_gt $first_version $second_version; then
echo "$first_version is greater than $second_version !"
fi

pro:

  • solid way to compare fancy version strings:

    • support any length of sub-parts (ie: 1.3alpha.2.dev2 > 1.1 ?)
    • support alpha-betical sort (ie: 1.alpha < 1.beta2)
    • support big size version (ie: 1.10003939209329320932 > 1.2039209378273789273 ?)
  • can easily be modified to support n arguments. (leaved as an exercise ;) )

    • usually very usefull with 3 arguments: (ie: 1.2 < my_version < 2.7 )

cons:

  • uses a lot of various calls to different programs. So it's not that efficient.
  • uses a pretty recent version of sort and it might not be available on your
    system. (check with man sort)

without sort -V:

## each separate version number must be less than 3 digit wide !
function version { echo "$@" | gawk -F. '{ printf("%03d%03d%03d\n", $1,$2,$3); }'; }

example usage:

first_version=5.100.2
second_version=5.1.2
if [ "$(version "$first_version")" -gt "$(version "$second_version")" ]; then
echo "$first_version is greater than $second_version !"
fi

pro:

  • quicker solution as it only calls 1 subprocess
  • much more compatible solution.

cons:

  • quite specific, version string must:

    • have version with 1, 2 or 3 parts only. (excludes '2.1.3.1')
    • each parts must be numerical only (excludes '3.1a')
    • each part can't be greater than 999 (excludes '1.20140417')

Comments about your script:

I can't see how it could work:

  • as stated in a comment > and < are very special shell character and you should replace them by -gt and -lt
  • even if you replaced the characters, you can't compare version numbers as if they where integers or float. For instance, on my system, php version is 5.5.9-1ubuntu4.

But your function version() is quite cleverly written already and may help you by circumventing the classical issue that sorting alphabetically numbers won't sort numbers numerically ( alphabetically 1 < 11 < 2, which is wrong numerically). But be carefull: arbitrarily large numbers aren't supported by bash (try to keep under 32bits if you aim at compatibility with 32bits systems, so that would be 9 digit long numbers). So I've modified your code (in the second method NOT using sort -V) to force only 3 digits for each part of the version string.

EDIT: applied @phk amelioration, as it is noticeably cleverer and remove a subprocess call in the first version using sort. Thanks.

How to compare 2 strings alphabetically in PHP?

Use strcmp. If the first argument to strcmp is lexicographically smaller to the second, then the value returned will be negative. If both are equal, then it will return 0. And if the first is lexicograpically greater than the second then a positive number will be returned.

nb. You probably want to use strcasecmp(string1,string2), which ignores case...

C# how can you compare versions?

Use the semantic version library for .Net

To install the package:

 Install-Package semver

You can parse /compare versions.

Example 1: Compare

     var v1 = new SemVersion(1, 0, 0, "rc1");
Console.WriteLine(v1);
var v2 = new SemVersion(1, 0, 0, "rc2");
Console.WriteLine(v2);
var r = SemVersion.Compare(v1,v2);
//If v1 < v2 return -1
//if v1 > v2 return +1
//if v1 = v2 return 0
Console.WriteLine(r); // -1

Example2: Parse

     var version = SemVersion.Parse("1.2.45-alpha-beta+nightly.23.43-bla");
Console.WriteLine(version);
Console.WriteLine( version.Major); //1
Console.WriteLine( version.Minor); //2
Console.WriteLine( version.Patch); //45
Console.WriteLine(version.Prerelease); //alpha-beta
Console.WriteLine(version.Build); //nightly.23.43

Update:

Life demo in fiddle

How can I compare software version number using JavaScript? (only numbers)

The basic idea to make this comparison would be to use Array.split to get arrays of parts from the input strings and then compare pairs of parts from the two arrays; if the parts are not equal we know which version is smaller.

There are a few of important details to keep in mind:

  1. How should the parts in each pair be compared? The question wants to compare numerically, but what if we have version strings that are not made up of just digits (e.g. "1.0a")?
  2. What should happen if one version string has more parts than the other? Most likely "1.0" should be considered less than "1.0.1", but what about "1.0.0"?

Here's the code for an implementation that you can use directly (gist with documentation):

function versionCompare(v1, v2, options) {
var lexicographical = options && options.lexicographical,
zeroExtend = options && options.zeroExtend,
v1parts = v1.split('.'),
v2parts = v2.split('.');

function isValidPart(x) {
return (lexicographical ? /^\d+[A-Za-z]*$/ : /^\d+$/).test(x);
}

if (!v1parts.every(isValidPart) || !v2parts.every(isValidPart)) {
return NaN;
}

if (zeroExtend) {
while (v1parts.length < v2parts.length) v1parts.push("0");
while (v2parts.length < v1parts.length) v2parts.push("0");
}

if (!lexicographical) {
v1parts = v1parts.map(Number);
v2parts = v2parts.map(Number);
}

for (var i = 0; i < v1parts.length; ++i) {
if (v2parts.length == i) {
return 1;
}

if (v1parts[i] == v2parts[i]) {
continue;
}
else if (v1parts[i] > v2parts[i]) {
return 1;
}
else {
return -1;
}
}

if (v1parts.length != v2parts.length) {
return -1;
}

return 0;
}

This version compares parts naturally, does not accept character suffixes and considers "1.7" to be smaller than "1.7.0". The comparison mode can be changed to lexicographical and shorter version strings can be automatically zero-padded using the optional third argument.

There is a JSFiddle that runs "unit tests" here; it is a slightly expanded version of ripper234's work (thank you).

Important note: This code uses Array.map and Array.every, which means that it will not run in IE versions earlier than 9. If you need to support those you will have to provide polyfills for the missing methods.

Comparing different strings in PHP with == returns true

<?php
$a=6064365413078728979;
$b=6064365413078728452;
echo $a."<br>".$b;
//var_dump( $a==$b );
die();
?>

When you run that, then on your machine that might be exceeding limit for a number and that is a numeric comparison taking place. Try the script above and see value for $a will probably be different than the value you gave.

That is why when both are compared numerically they are equal. Hence use === as suggested by others

Edit: Explanation based upon @Axel's Advice.

PHP Manual explains

The size of a float is platform-dependent, although a maximum of
~1.8e308 with a precision of roughly 14 decimal digits is a common
value (the 64 bit IEEE format).

And this website is offering and explanation on the Overflow phenomenon and a small php code to test your system's integer and float range. Getting to know the limit on your servers will most probably explain it best why the offerflow occured



Related Topics



Leave a reply



Submit