A common version number contains sequences of digits, sequences of letters, and punctuation marks.
The string is viewed as a sequence of components. The components are compared with corresponding components, from left-to-right.
A component is one of the following:
- A series of digits. They are compared as numbers (“11” > “2”).
- A series of ASCII letters. They are compared as strings, case-insensitive.
- A series of punctuation marks, loosely defined as everything else. They are compared as match/no-match only. A no-match is considered an exception, and prevents greater/less comparisons from working at all.
The parts are compared from left-to-right. If the parts match up to the point where one string runs out of parts, the one with parts left over is Larger. For example, “1.23.45” < “1.23.45b”. The left string has 5 parts (3 series’ of digits, two series’ of punctuation marks); the right string has 6 parts.
Strings that don’t work with this algorithm are those that use words, dates, or non-left-to-right ordering of parts.
This was written before Perl provided the "v-string" literal. But, it is not limited to just numbers and dots. It handles most any reasonable version naming system, including other delimiters and letters as well as numbers.
{
my $splitter= qr/\d+|[A-Za-z]+|[^0-9A-Za-z]+/;
sub compare_version_string ($$)
# returns <0, 0, >0 to indicate less, eq, or greater-than.
# dies (exception) if no relation exists.
{
my ($left, $right)= @_;
my @left= $left =~ /$splitter/g;
my @right= $right =~ /$splitter/g;
print "@left\n";
print "@right\n";
my $r;
while (@left && @right) {
$left= shift @left;
$right= shift @right;
if ($left =~ /^\d+$/ && $right =~ /^\d+$/) {
# compare as numbers
$r= $left <=> $right;
return $r if $r; # or keep going if zero.
}
elsif ($left =~ /^[A-Za-z]+$/ && $right =~ /^[A-Za-z]+$/) {
# compare as strings
$r= $left cmp $right;
return $r if $r; # or keep going if zero.
}
elsif ($left =~ /^[^0-9A-Za-z]+$/ && $right =~ /^[^0-9A-Za-z]+$/
+) {
# delimter or "other", much match exact.
die "version strings are not compatible.\n" unless $left eq $r
+ight;
}
else {
# the parts are not of the same type
die "version strings are not compatible.\n";
}
}
# one of the strings ran out of parts.
return scalar(@left) <=> scalar(@right);
}
}
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.