# Perl Weekly Challenge 275: Replace Digits
These are some answers to the Week 275, Task 2, of the Perl Weekly Challenge organized by Mohammad S. Anwar.
Task 2: Replace Digits
You are given an alphanumeric string, $str
, where each character is either a letter or a digit.
Write a script to replace each digit in the given string with the value of the previous letter plus (digit) places.
Example 1
Input: $str = 'a1c1e1'
Ouput: 'abcdef'
shift('a', 1) => 'b'
shift('c', 1) => 'd'
shift('e', 1) => 'f'
Example 2
Input: $str = 'a1b2c3d4'
Output: 'abbdcfdh'
shift('a', 1) => 'b'
shift('b', 2) => 'd'
shift('c', 3) => 'f'
shift('d', 4) => 'h'
Example 3
Input: $str = 'b2b'
Output: 'bdb'
Example 4
Input: $str = 'a16z'
Output: 'abgz'
I have several comments about this task.
First, we're not told what to do if shifting a letter by a given offset leads to going past the last letter of the alphabet. For example, what is the value of shift('z', 2)
? Shall we take the next character in the ASCII order? Or do we go back to the beginning of the alphabet, as in the Caesar cipher? We don't have any instruction here, so I'll not consider this case and just shift in the ASCII order, even though this may lead to unprintable characters (but not with the examples provided). It would not really be difficult to choose the other solution and rotate around the alphabet, but this is left as an exercise to the reader.
Next, we also don't know what to do with an input string starting with a digit, and also don't have an example clarifying that. I'll consider that this will not happen and that all input strings will start with an alphabetical character, as the examples provided.
Finally, we also don't know that to do with input string with two digits in a row. The task says to "to replace each digit in the given string with the value of the previous letter plus (digit) places." We cannot do that when the previous letter is not a letter, but a digit, unless we do that after the previous digit has already been converted to a letter. But then, I disagree with Example 4 ('a16z'): if we convert the third character ("6") after the second one ("1") has already been shifted to a "b", then the third letter ought to be a "h", not a "g".
Replace Digits in Raku
This solution should be viewed in the context of the above comments.
sub replace-digits ($in) {
my @chars = $in.comb;
for 1..@chars.end -> $i {
if @chars[$i] ~~ /\d/ {
@chars[$i] = chr( @chars[$i-1].ord + @chars[$i]);
}
}
return join "", @chars;
}
my @tests = 'a1c1e1', 'a1b2c3d4', 'b2b', 'a16z';
for @tests -> $test {
printf "%-10s => ", $test;
say replace-digits $test;
}
This program displays the following output:
$ raku ./replace-digits.raku
a1c1e1 => abcdef
a1b2c3d4 => abbdcfdh
b2b => bdb
a16z => abhz
Replace Digits in Perl
This a port to Perl of the above Raku program. All the comments above also apply here, including the reason why my result with the fourth example ("a16z") disagrees with the example provided in the task specification.
use strict;
use warnings;
use feature 'say';
sub replace_digits {
my @chars = split //, shift;
for my $i (1..$#chars) {
if ($chars[$i] =~ /\d/) {
$chars[$i] = chr( $chars[$i] + ord $chars[$i-1]);
}
}
return join "", @chars;
}
my @tests = ('a1c1e1', 'a1b2c3d4', 'b2b', 'a16z');
for my $test (@tests) {
printf "%-10s => ", $test;
say replace_digits $test;
}
This program displays the following output:
$ perl ./replace-digits.pl
a1c1e1 => abcdef
a1b2c3d4 => abbdcfdh
b2b => bdb
a16z => abhz
Wrapping up
The next week Perl Weekly Challenge will start soon. If you want to participate in this challenge, please check https://perlweeklychallenge.org/ and make sure you answer the challenge before 23:59 BST (British summer time) on July 7, 2024. Happy Independence Day to all my friends in the US. And, please, also spread the word about the Perl Weekly Challenge if you can.
Leave a comment