diff options
| author | PerlMonk Athanasius <PerlMonk.Athanasius@gmail.com> | 2020-05-16 23:44:50 -0700 |
|---|---|---|
| committer | PerlMonk Athanasius <PerlMonk.Athanasius@gmail.com> | 2020-05-16 23:44:50 -0700 |
| commit | ea71158dff34e84024f8bc9333010104e4503e7a (patch) | |
| tree | 5369354c430d22669d3d6b7be38287aa8aaa91a9 /challenge-060 | |
| parent | 36f57247358bdfce5419157c0fd9b984759c9680 (diff) | |
| download | perlweeklychallenge-club-ea71158dff34e84024f8bc9333010104e4503e7a.tar.gz perlweeklychallenge-club-ea71158dff34e84024f8bc9333010104e4503e7a.tar.bz2 perlweeklychallenge-club-ea71158dff34e84024f8bc9333010104e4503e7a.zip | |
Perl and Raku solutions to Task 1 of the Perl Weekly Challenge #060
On branch branch-for-challenge-060
Changes to be committed:
new file: challenge-060/athanasius/perl/ch-1.pl
new file: challenge-060/athanasius/raku/ch-1.raku
Diffstat (limited to 'challenge-060')
| -rw-r--r-- | challenge-060/athanasius/perl/ch-1.pl | 132 | ||||
| -rw-r--r-- | challenge-060/athanasius/raku/ch-1.raku | 124 |
2 files changed, 256 insertions, 0 deletions
diff --git a/challenge-060/athanasius/perl/ch-1.pl b/challenge-060/athanasius/perl/ch-1.pl new file mode 100644 index 0000000000..96daf3ce58 --- /dev/null +++ b/challenge-060/athanasius/perl/ch-1.pl @@ -0,0 +1,132 @@ +#!perl + +################################################################################ +=comment + +Perl Weekly Challenge 060 +========================= + +Task #1 +------- +*Excel Column* + +*Reviewed by: Ryan Thompson* + +Write a script that accepts a number and returns the *Excel Column Name* it +represents and vice-versa. + +Excel columns start at *A* and increase lexicographically using the 26 letters +of the English alphabet, *A*..*Z*. After *Z*, the columns pick up an extra +"digit", going from *AA*, *AB*, etc., which could (in theory) continue to an +arbitrary number of digits. In practice, Excel sheets are limited to 16,384 +columns. + +*Example* + +Input Number: 28 Output: AB + +Input Column Name: AD Output: 30 + +=cut +################################################################################ + +#--------------------------------------# +# Copyright © 2020 PerlMonk Athanasius # +#--------------------------------------# + +use strict; +use warnings; +use Const::Fast; +use Scalar::Util qw( looks_like_number ); +use constant WARN_ON_RANGE => 1; + +const my $MAX_COLUMN => 16_384; # = XFD: 24*26² + 6*26¹ + 4*26⁰ + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + $| = 1; + print "\n"; +} + +#=============================================================================== +MAIN: +#=============================================================================== +{ + print "Challenge 060, Task #1: Excel Column (Perl)\n\n"; + + my $args = scalar @ARGV; + $args == 1 + or die "ERROR: Expected 1 command-line argument but found $args\n"; + + my $arg = $ARGV[0]; + + if (looks_like_number($arg)) + { + int($arg) == $arg && $arg > 0 + or die "ERROR: Invalid numeric argument \"$arg\"\n"; + + warn "WARNING: Column $arg is out of range\n" + if WARN_ON_RANGE && $arg > $MAX_COLUMN; + + my $name = number_to_name($arg); + + print "The Excel column number $arg is named \"$name\"\n"; + } + else + { + my $name = uc $arg; + $name =~ / ^ [A-Z]+ $ /x + or die "ERROR: Argument \"$arg\" is not a valid column name\n"; + + my $number = name_to_number($name); + + warn "WARNING: Column \"$name\" is out of range\n" + if WARN_ON_RANGE && $number > $MAX_COLUMN; + + print "The Excel column named \"$name\" is number $number\n"; + } +} + +#------------------------------------------------------------------------------- +sub number_to_name +#------------------------------------------------------------------------------- +{ + my ($num) = @_; + my $name = ''; + my $exp = 2; + my $max = 26; # Cf. OEIS A218729: + $max += 26 ** $exp++ while $max < $num; # 1, 27, 703, 18279, ... + + for my $power (reverse 0 .. $exp - 2) + { + my $div = 26 ** $power; + my $quo = int($num / $div); + $quo = 26 if $quo > 26; + $name .= ('A' .. 'Z')[$quo - 1]; + $num -= $quo * $div; + + last if $num == 0; + } + + return $name; +} + +#------------------------------------------------------------------------------- +sub name_to_number +#------------------------------------------------------------------------------- +{ + my ($name) = @_; + my $number = 0; + + for (my $multiplier = 1; $name; $multiplier *= 26) + { + my $char = substr $name, -1, 1, ''; + $number += $multiplier * (ord($char) - ord('A') + 1); + } + + return $number; +} + +################################################################################ diff --git a/challenge-060/athanasius/raku/ch-1.raku b/challenge-060/athanasius/raku/ch-1.raku new file mode 100644 index 0000000000..63e70d612b --- /dev/null +++ b/challenge-060/athanasius/raku/ch-1.raku @@ -0,0 +1,124 @@ +use v6d; + +################################################################################ +=begin comment + +Perl Weekly Challenge 060 +========================= + +Task #1 +------- +*Excel Column* + +*Reviewed by: Ryan Thompson* + +Write a script that accepts a number and returns the *Excel Column Name* it +represents and vice-versa. + +Excel columns start at *A* and increase lexicographically using the 26 letters +of the English alphabet, *A*..*Z*. After *Z*, the columns pick up an extra +"digit", going from *AA*, *AB*, etc., which could (in theory) continue to an +arbitrary number of digits. In practice, Excel sheets are limited to 16,384 +columns. + +*Example* + +Input Number: 28 Output: AB + +Input Column Name: AD Output: 30 + +=end comment +################################################################################ + +#--------------------------------------# +# Copyright © 2020 PerlMonk Athanasius # +#--------------------------------------# + +my Bool constant WARN-ON-RANGE = True; +my UInt constant MAX-COLUMN = 16_384; # = XFD: 24*26² + 6*26¹ + 4*26⁰ + +#------------------------------------------------------------------------------- +BEGIN ''.put; +#------------------------------------------------------------------------------- + +#=============================================================================== +multi sub MAIN +( + UInt:D $number where $number > 0 #= Excel column number: an integer >= 1 +) +#=============================================================================== +{ + "Challenge 060, Task #1: Excel Column (Raku)\n".put; + + "WARNING: Column $number is out of range".note + if WARN-ON-RANGE && $number > MAX-COLUMN; + + my Str $name = number-to-name($number); + + "The Excel column number $number is named \"$name\"".put; +} + +#------------------------------------------------------------------------------- +sub number-to-name( UInt:D $num is copy --> Str:D ) +#------------------------------------------------------------------------------- +{ + my Str $name = ''; + my UInt $exp = 2; + my UInt $max = 26; # Cf. OEIS A218729: + $max += 26 ** $exp++ while $max < $num; # 1, 27, 703, 18279, ... + + for reverse 0 .. $exp - 2 -> UInt $power + { + my UInt $div = 26 ** $power; + my UInt $quo = ($num / $div).truncate; + $quo = 26 if $quo > 26; + $name ~= ('A' .. 'Z')[$quo - 1]; + $num -= $quo * $div; + + last if $num == 0; + } + + return $name; +} + +#=============================================================================== +multi sub MAIN +( + Str:D $str #= Excel column name: one or more letters only +) +#=============================================================================== +{ + "Challenge 060, Task #1: Excel Column (Raku)\n".put; + + my Str $name = $str.uc; + + $name ~~ rx/ ^ <[ A .. Z ]>+ $ / + or die "ERROR: Argument \"$str\" is not a valid column name\n$*USAGE"; + + my UInt $number = name-to-number($name); + + "WARNING: Column \"$name\" is out of range".note + if WARN-ON-RANGE && $number > MAX-COLUMN; + + "The Excel column named \"$name\" is number $number".put; +} + +#------------------------------------------------------------------------------- +sub name-to-number( Str:D $name --> UInt:D ) +#------------------------------------------------------------------------------- +{ + my UInt $number = 0; + my UInt $multiplier = 1; + my Str @chars = $name.split: '', :skip-empty; + + while @chars + { + my Str $char = @chars.pop; + $number += $multiplier * ($char.ord - 'A'.ord + 1); + $multiplier *= 26; + } + + return $number; +} + +############################################################################### |
