zek152 has asked for the wisdom of the Perl Monks concerning the following question:

Greetings great monks.

I need to compare 2 revision numbers to see if they are the same. The difficulty is that "*" are used as wildcards. The terminology used is major_number.minor_number. My code worked just fine until people started using wildcards for minor numbers

Example: Rev1 | Rev2 | Result | 02.10 | 02.10 | Equal | 2.1 | 02.10 | Equal | 02.10 | * | Equal | 02.10 | 02.* | Equal |

I believe that astrisks will only be used for minor numbers (wouldnt make sense for major). Thanks.

Update: I included the code I tried to solve the problem. The issue is handling wildcards and empty strings

sub rev_compare() { #Args: 2 rev strings the section rev first and the master rev second #Returns a 1 if they match and a 0 if they do not #this sub takes 2 REV strings and compares them my $section_raw_rev_string = shift; my $main_raw_rev_string = shift; my $main_major_number = ""; my $main_minor_number = ""; my $section_major_number = ""; my $section_minor_number = ""; if ($section_raw_rev_string eq "*") { return 1; } if ($main_raw_rev_string =~ /(.+)\.(.+)/) { $main_major_number = $1; $main_minor_number = $2; } if ($section_raw_rev_string =~ /(.+)\.(.+)/) { $section_major_number = $1; $section_minor_number = $2; } if ($main_raw_rev_string eq $section_raw_rev_string) { return 1; } if ($section_raw_rev_string eq "*") { return 1; } if ($section_major_number == $main_minor_number) { if ($section_minor_number eq "*") { return 1; } if ($section_minor_number == $main_minor_number) { return 1; } } return 0; }

Update: I located the offending code (if ($section_major_number == $main_minor_number) The $main_minor_number should have been $main_major_number. If there is a better way to do this please let me know because it feels like a hacked together jury-rigged piece of crap

Replies are listed 'Best First'.
Re: Comparing revision numbers
by moritz (Cardinal) on Jul 12, 2010 at 18:04 UTC

    The problem is in line 42 of your code.

    (Or phrased differently, if you showed your code, it would be much easier to help you).

    Update:

    Running your code with

    use strict; use warnings; # your code here... print rev_compare('1.3', '*');

    Results in an error:

    Too many arguments for main::rev_compare at foo.pl line 54, near "'*') +" Execution of foo.pl aborted due to compilation errors.

    Removing the () after the sub rev_compare fixes this. Then I get

    Argument "" isn't numeric in numeric eq (==) at foo.pl line 39. 0
    Line 39 is     if ($section_major_number == $main_minor_number)

    Which reveals a problem of your code: you don't have sane handling for when the numbers don't contain a dot. Also you only check the first argument for being an asterisk, not the second.

    I'd suggest this code instead:

    sub rev_compare { my $section = shift; my $main = shift; return 1 if $section eq '*' or $main eq '*'; my @section = split /\./, $section; my @main = split /\./, $main; return ($section[0] == $main[0]) && (($section[1] eq '*' && $main[1] eq '*') || $section[1] == $main[1]); }

    I haven't tested it with all values, but it should handle * as the value of the minor version number just fine

    Perl 6 - links to (nearly) everything that is Perl 6.

      My apologies. I have updated the original post.

      Update. Thanks, I felt like i was going about it really poorly. Thanks for the help.

Re: Comparing revision numbers
by Corion (Patriarch) on Jul 12, 2010 at 18:31 UTC

    You could cheat and normalize and then convert the revision on the left side into all potentially matching revisions and then check whether the right side is one of those:

    • 2.10
    • 2.*
    • *
    #!perl -w use strict; my $left = '2.10'; my $right = '02.10'; sub normalize { # just strip leading zeroes my ($ver) = @_; $ver =~ s/^0+//; $ver }; sub candidates { my ($ver) = @_; my @res = normalize $ver; (my $minor_wild = $ver) =~ s/\.\d+/*/; push @res, $minor_wild; push @res, '*' unless $ver eq '*'; @res }; for my $right (qw(2.0 2.1 2.10 02.10 2.*)) { print join("\t", $left, $right, (grep { $right eq $_ } candidates( +$left)) ? 'equal' : 'inequal'), "\n"; };