Perl Weekly Challenge: Week 341
Challenge 1:
Broken Keyboard
You are given a string containing English letters only and also you are given broken keys.
Write a script to return the total words in the given sentence can be typed completely.
Example 1
Input: $str = 'Hello World', @keys = ('d')
Output: 1
With broken key 'd', we can only type the word 'Hello'.
Example 2
Input: $str = 'apple banana cherry', @keys = ('a', 'e')
Output: 0
Example 3
Input: $str = 'Coding is fun', @keys = ()
Output: 3
No keys broken.
Example 4
Input: $str = 'The Weekly Challenge', @keys = ('a','b')
Output: 2
Example 5
Input: $str = 'Perl and Python', @keys = ('p')
Output: 1
We can solve this as a one-liner in Raku.
We take the string provided in the first command-line argument and separate into words with .words()
. Then we
filter those words with .grep()
, matching each one against a regular expression which contains the second command-line argument (representing the broken keys) split into individual characters with .comb()
and interpolated
into the regular expression with @()
. This acts as a custom character class. We use the i
(case-insnsitive) flag so we have to use the explicit name of the match operator, m
, If a word doesnot_ match this regular expression it
means it has no broken keys. We count the number of such words with .elems()
and print the result with .say()
.
@*ARGS[0].words.grep({ $_ !~~ m:i/ @(@*ARGS[1].comb) / }).elems.say
For example 3, @keys
is empty. I modeled that in Raku by just having an empty second command-line argument but it seems you can't do that in Perl. So instead I just let the second argument be omitted and there is a line in my solution like this:
my $broken = shift // q{.};
If the second argument is not defined, $broken
becomes .
. In regular expressions, that will match any character
so all words will match.
The rest of it works the same as Raku but with different syntax.
say scalar grep { !/[$broken]/i } split /\s+/, $str;
Challenge 2:
Reverse Prefix
You are given a string,
$str
and a character in the given string,$char
.Write a script to reverse the prefix upto the first occurrence of the given $char in the given string $str and return the new string.
Example 1
Input: $str = "programming", $char = "g"
Output: "gorpramming"
Reverse of prefix "prog" is "gorp".
Example 2
Input: $str = "hello", $char = "h"
Output: "hello"
Example 3
Input: $str = "abcdefghij", $char = "h"
Output: "hgfedcbaij"
Example 4
Input: $str = "reverse", $char = "s"
Output: "srevere"
Example 5
Input: $str = "perl", $char = "r"
Output: "repl"
This time, I will start with Perl first. The substitution operator s///
is applied to $str
.
In the first half, the start of $str
up to $char
is matched. In the second half, the matched text
is reverse()
d and the reverse text is substituted for the original. We need to use the e
switch for s///
ti allow code in the second half and the x
switch to allow whitespace in the first half making it a little more
readable.
$str =~ s/(^ .+? $char)/reverse $1/ex;
Then we print out the modified string with say()
.
say $str;
In Raku we can do all of this in one line. I saved a few characters by using the first and second command-line
arguments as is instead of assigning them to $str
and $char
. Also because these arguments are immutable, we have to use S/// ... given
, the non-destructive version of the substitution operator. One last minor difference to note
is that in Raku, strings are reversed with .flip()
not .reverse()
which is exclusively for lists and arrays.
say S/ (^ .+? $(@*ARGS[1])) /$($0.flip)/ given @*ARGS[0]