28 June 2024 | Challenge 275 |
Replacing the Broken Keys
Task 1: Broken Keys
Submitted by: Mohammad Sajid Anwar
You are given a sentence, $sentence
and list of broken keys @keys
.
Write a script to find out how many words can be typed fully
.
Example 1
Input: $sentence = "Perl Weekly Challenge", @keys = ('l', 'a')
Output: 0
Example 2
Input: $sentence = "Perl and Raku", @keys = ('a')
Output: 1
Only Perl since the other word two words contain 'a' and can't be typed fully.
Example 3
Input: $sentence = "Well done Team PWC", @keys = ('l', 'o')
Output: 2
Example 4
Input: $sentence = "The joys of polyglottism", @keys = ('T')
Output: 2
Solution
A word is typeable, if it does not contain any letters from one of the broken keys independent of its case. Thus we may create a character class containing the complement of the broken ones and match strings that completely consists of typeable characters.
When interpolating the dereferenced array ref of broken keys, we ignore the inserted blanks using the /xx
modifier that is available in perl v5.26.
Finally, the generated regex is applied via grep
to each word from the string.
In scalar context, this gives the requested word count.
use v5.26;
use warnings;
sub broken_keys {
my $typeable = qr{^[^@{+shift}]+$}ixx;
grep /$typeable/, split /\s+/, shift;
}
See the full solution to task 1.
Task 2: Replace Digits
Submitted by: Mohammad Sajid Anwar
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'
Solution
There are some cases not covered by the description or the examples:
- Upper case letters are not forbidden, but there are no concerning instructions.
- Strings starting with a digit are not forbidden, but these don’t have a previous letter.
- A shift from some letters may fall beyond the last letter, be it
z
orZ
.
To address these cases, some additional rules are established:
- The shift respects the case of the previous letter.
- Strings starting with a digit are assumed to have an implicit
A
as the previous letter. - Cyclic wrapping:
shift('Z', 1) => 'a'
andshift('z', 1) => 'A'
.
We use an array @d2a
and a hash %a2i
to convert digits to alpha and alpha to indices respectively, that are pre-initialized in a BEGIN
block.
use strict;
use warnings;
{
my (@d2a, %a2i);
BEGIN {
@d2a = ('A' .. 'Z', 'a' .. 'z');
@a2i{@d2a} = (0 .. $#d2a);
}
sub replace_digits {
my $prev = 0;
join '', map /\d/ ? $d2a[($prev + $_) % @d2a] :
do {$prev = $a2i{$_} // die "Illegal char '$_'"; $_},
split //, shift;
}
}
See the full solution to task 2.
If you have a question about this post or if you like to comment on it, feel free to open an issue in my github repository.