Perl Weekly Challenge: Week 275

Challenge 1:

Broken Keys

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

The input comes from the command-line where the first argument provides $str and the rest @keys.

A regexp pattern by concatenating (with [~]) the delimiters of a custom character class with @keys.

my $keys = [~] '<[', @keys, ']>';

$str is split into a list of words with .words(). The character class we created in the previous line is interpolated into a regular expression (it has to be surrounded by <> unlike Perl.) and the i flag is added to make case-insensitive comparisons. (See example 4.) This is used with .grep() to filter the list for words that do not contain the regular expression. .elems() is used to count them and this number is printed out with .say().

$str.words.grep({ $_ !~~ m:i/ <$keys> / }).elems.say;

(Full code on Github.)

The Perl version works the same except join() is used instead of [~] and split() instead of .words().

my $keys = join q{}, ('[', @keys, ']');
say scalar grep { $_ !~ /$keys/i } split /\s+/, $str;

(nFull code on Github.)

Challenge 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'

my @input = $str.comb;
my $output;
my $current;

This one was easy.

The input was split into a list of characters and for each character...

for @input -> $c {

...if it is a digit, the numerical value of the current non-digit character is found with .ord(). The digit is added to it and the result is turned back to a character with .chr(). This is then appended to the output.

    if $c ~~ /\d/ {
        $output ~= chr($current.ord + $c);

If it is not a digit, the character is stored in $current. This is necessary for cases like e.g. example 4 where two consecutive digits have to be added to a character.

    } else {
        $current = $c;

Then the character is appended to the output.

        $output ~= $c;
    }
}

After all of @input has been processed, $outputis printed.

say $output;

(Full code on Github.)

This is the Perl version:

my @input = split //, $str;
my $output;
my $current;

for my $c (@input) {
    if ($c =~ /\d/) {
        $output .= chr(ord($current) + $c);
    } else {
        $current = $c;
        $output .= $c;
    }
}

say $output;

(Full code on Github.)