It’s the second week of the Perl Weekly Challenge, and like last week we’ve got two assignments — one “beginner” and one “advanced”.

The advanced assigment this time was: “Write a script that can convert integers to and from a base35 representation, using the characters 0–9 and A-Y.” Even though this is a blog mainly about Perl 6 I thought it’d be fun to start with my Perl 5 solutions to the advanced assigment, just so it’s even more easy to appreciate the simplicity of the Perl 6 solution… although not, as you will see, without some discussion.

PERL 5 # Convert from base35 to base10

perl -E '%d = map { $_ => $c++ } (0..9,A..Y); $i = 1; for (reverse(split("", @ARGV[0]))) { $e += $i * $d{$_}; $i = $i * 35; } say $e' 1M5

# Output: 2000 # Convert from base10 to base35

perl -E '%d = map { $c++ => $_ } (0..9,A..Y); while ($ARGV[0] > 0) { push @n, $d{$ARGV[0] % 35}; $ARGV[0] = int($ARGV[0] / 35); } say join("", reverse(@n));' 2000

# Output: 1M5

So these are working one-liners but hardly readable ones. They also violate a lot of best practices. So I expanded them into a full script that’s easier to reuse and understand with added strict and error handling as well as support for positive/negative (+and - prefixes).

#!/usr/bin/env perl

#

# Usage:

# perl base35.pl [+-]NUMBER FROM-BASE, e.g.

#

# perl base35.pl 1000 10

# Output: SK

#

# perl base35.pl SK 35

# Output: 1000

#

# perl base35.pl -SK 35

# Output: -1000 use v5.18; say base35_conv( @ARGV );

my ($no, $base) = (uc(shift), shift);

if ($base != 10 && $base != 35) {

warn "Not a valid base, must be 10 or 35";

return -1;

}

if (($base == 35 && $no !~ /^[\+\-]{0,1}[0-9A-Y]+$/) || ($base == 10 && $no !~ /^[\+\-]{0,1}[0-9]+$/)) {

warn "You have to provide a valid number for the given base";

return -1;

}

my ($c, $e) = (0, 0);

my $prefix = $no =~ s/^(\+|-)// ? $1 : "";

my %d = map { if ($base == 35) { $_ => $c++ } else { $c++ => $_ } } (0..9,'A'..'Y');

if ($base == 35) {

my $i = 1;

for (reverse(split("", $no))) {

$e += $i * $d{$_};

$i = $i * 35;

}

}

else {

my

while ($no > 0) {

push

$no = int($no / 35);

}

$e = join("", reverse(

}

return ( $prefix ? $prefix : "" ) . $e;

} sub base35_conv {my ($no, $base) = (uc(shift), shift);if ($base != 10 && $base != 35) {warn "Not a valid base, must be 10 or 35";return -1;if (($base == 35 && $no !~ /^[\+\-]{0,1}[0-9A-Y]+$/) || ($base == 10 && $no !~ /^[\+\-]{0,1}[0-9]+$/)) {warn "You have to provide a valid number for the given base";return -1;my ($c, $e) = (0, 0);my $prefix = $no =~ s/^(\+|-)// ? $1 : "";my %d = map { if ($base == 35) { $_ => $c++ } else { $c++ => $_ } } (0..9,'A'..'Y');if ($base == 35) {my $i = 1;for (reverse(split("", $no))) {$e += $i * $d{$_};$i = $i * 35;else {my @digits while ($no > 0) {push @digits , $d{$no % 35};$no = int($no / 35);$e = join("", reverse( @digits ));return ( $prefix ? $prefix : "" ) . $e;

There’s really not much to comment about the code above. It works and is reasonably readable. It’s quite long, however, and that’s where Perl 6 comes in and destroys it.

PERL 6 # Convert from base35 to base10

perl6 -e 'say "1M5".parse-base(35)'

# Output: 2000 # Convert from base10 to base35

perl6 -e 'say 2000.base(35)'

# Output: 1M5

At this you’re allowed to stop for a second an appreciate the simplicity of Perl 6. But:

Since these are built-in functions in Perl 6 this wasn’t — in my opinion — the best Perl 6 assigment. I guess the point of the assigment is to write a solution from scratch —had I solved the Perl 5 version of the assigment by using a ready-made CPAN module such as Math::Int2Base I’d feel that I cheated. Maybe that’s just me?