Skip to content

VersionPathSorter

Vitalii Koshura edited this page Apr 2, 2023 · 2 revisions

use strict;

# Read all lines from STDIN or file

my @lines = <>;

# Remove terminating newline from each line

foreach (@lines) {
   chomp
}

# Function to compare version numbers like "7.1.2"

sub compare_version_numbers {
   my ($l,$r) = @_;
   my @lx = split("\\.",$l);
   my @rx = split("\\.",$r);
   my $minlen = (@lx < @rx) ? @lx : @rx;
   for (my $i=0; $i < $minlen; $i++) {
      # make numeric by multiplying with 1
      my $l_number = ($lx[$i] * 1);
      my $r_number = ($rx[$i] * 1);
      # compare with spaceship operator
      my $l_vs_r = ($l_number <=> $r_number);
      # return if decision is clear!
      if ($l_vs_r != 0) {
         return $l_vs_r
      }
      # otherwise, next part in array of version numbers
   }
   # if we are here, we could not decide - shortest entry wins!
   return @lx <=> @rx
}

# Function to compare whole paths like "client_release/7.2/7.2.25"
# As it is called from "sort", the values are passed in via "$a" and "$b"

sub compare_paths {
   my @ax = split("/",$a);
   my @bx = split("/",$b);
   my $minlen = (@ax < @bx) ? @ax : @bx;
   for (my $i=0; $i < $minlen; $i++) {
      # Check whether we have version numbers at position $i
      my $a_is_vnum = ($ax[$i] =~ /^[\d\.]+$/);
      my $b_is_vnum = ($bx[$i] =~ /^[\d\.]+$/);
      if ($a_is_vnum && !$b_is_vnum) {
         # "a" version number before "b": b wins
         return 1
      }
      if (!$a_is_vnum && $b_is_vnum) {
         # "b" is version number before "a": a wins
         return -1
      }
      if (!$a_is_vnum && !$b_is_vnum && $ax[$i] ne $bx[$i]) {
         # both are not version numbers and both are unequal: compare the strings
         return $ax[$i] cmp $bx[$i]
      }
      if ($a_is_vnum && $b_is_vnum && $ax[$i] ne $bx[$i]) {
         # both are unequal version numbers: compare the version number
         # print STDERR $ax[$i] . " vs " . $bx[$i];
         my $sn = compare_version_numbers($ax[$i],$bx[$i]);
         # print STDERR " = " . $sn . "\n";
         if ($sn != 0) {
            return $sn
         }
      }
      # otherwise, next part in array of path elements
   }
   # if we are here, we could not decide - shortest entry wins!
   return @ax <=> @bx
}

# Sort and print

my @sorted = sort compare_paths @lines;

foreach (@sorted) {
   print "$_\n"
}
Clone this wiki locally