iamnewbie
iamnewbie

Reputation: 13

Write a program to compare 2 versions using perl

Is the below program correct to compare two versions? say v1 = 3.0.1 and v2 = 4.5.5

sub VerChecker
{
my $v1 = shift;
my $v2 = shift;

my @v1_parts = split (/./, $v1);
my @v2_parts = split (/./, $v2);

for( my $i = 0; $i < @v1_parts; $i++ ) 
{
if( $v1_parts[$i] < $v2_parts[$i] ) 
{
return -1;
}
elsif( $v1_parts[$i] > $v2_parts[$i] )
{
return 1;
}
}

 # equal !
 return 0;
}

Can you correct the above code

Upvotes: 0

Views: 225

Answers (1)

David K-J
David K-J

Reputation: 928

#!/bin/env perl
use strict;
use warnings;

sub ver_checker {
    my ($v1, $v2) = @_;

    my @v1_parts = split(/\./, $v1);
    my @v2_parts = split(/\./, $v2);

    my $num_parts = scalar @v1_parts;
    if (scalar @v2_parts > $num_parts) {
        $num_parts = scalar @v2_parts;
    }

    for my $part (0 .. $num_parts-1) {
        $v1_parts[$part] = sprintf("%04d", $v1_parts[$part] // 0);
        $v2_parts[$part] = sprintf("%04d", $v2_parts[$part] // 0);
    }

    return join('', @v1_parts) cmp join('', @v2_parts);
}

print ver_checker('3.0.1', '4.5.5')."\n";
print ver_checker('3.0', '4.5.5')."\n";
print ver_checker('3.0.1', '4')."\n";
print ver_checker('5', '4')."\n";

A few things to mention:

  1. use strict; use warnings; always
  2. Camel Case Isn't Fun Anymore. Use lowercase_and_underscores
  3. Escape literals in regular expressions. Your split needed to escape the period
  4. I find that when comparing something dotted like this, it's easier to pad everything out and compare the string. Your code only considered if the version number was three dotted numbers. I made it more portable by making it choose the longest dotted number and pad both out (ie. 3.1 vs 5.0.1 essentially becomes 3.1.0 vs 5.0.1, and pads to 000300010000 vs 000500000001. cmp returns your -1/0/1 value.

To clarify why your split wasn't working: Your split needed to escape the period. You were splitting on every character, which meant there were no captures. Run this script to see for yourself.

#!/bin/env perl
use strict; use warnings;
use Data::Dumper;

my $foo = 'a.b.c';
my @split1 = split(/./, $foo); # gives []
my @split2 = split(//, $foo); # gives ['a', '.', 'b', '.', 'c']
my @split3 = split(/\./, $foo); # gives [ 'a', 'b', 'c']
print Dumper [ \@split1, \@split2, \@split3 ];

Upvotes: 1

Related Questions