This is my response to The Weekly Challenge #341.
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
It follows from the examples that spaces should be allowed in the strings, even though thay cannot in any way be considered English letters.
File: broken-keyboard
#! /usr/bin/env raku
unit sub MAIN (:s(:$str) where $str ~~ /^ <[a..z A..Z \s]>+ $/, # [1]
:k(:$keys) where $keys ~~ /^ <[a..z]>* $/, # [2]
:v(:$verbose));
my @words = $str.lc.words; # [3]
my @keys = $keys.lc.comb; # [4]
my @typeable = @words.grep({ .contains(none(@keys)) }); # [5]
die "Duplicate keys" if @keys.repeated; # [6]
if $verbose
{
say ": Words: { @words.map({ "'$_'" }).join(", ") }";
say ": Keys: { @keys.map({ "'$_'" }).join(", ") }";
say ": Typeable words: { @typeable.map({ "'$_'" }).join(", ") }";
}
say @typeable.elems; # [7]
[1] A named argument for the string, containing English letters (upper- as well as lowercase) and spaces. With at least one character.
[2] Another named argument; this one for the broken keys - as a string. It can have zero length, to satisfy the third example.
[3]
Convert the string into lowercase (to satisfy the fifth
example) with lc
, and get the words with words
.
See docs.raku.org/routine/lc for more information about lc
.
See docs.raku.org/routine/words for more information about words
.
[4] Convert the key string to lowercase, and split them into
an array of individual characters with comb
.
See docs.raku.org/routine/comb for more information about comb
.
[5] Get the typeable words; those that does not contain any of the broken keys - or «contains none of the broken keys» as the program expresses it.
See docs.raku.org/routine/contains for more information about contains
.
[6] Terminate the program if we have duplicate keys.
See docs.raku.org/routine/repeated for more information about repeated
.
[7] Print the number of typeable words.
Running it:
$ ./broken-keyboard -s='Hello World' -k=d
1
$ ./broken-keyboard -s='apple banana cherry' -k=ae
0
$ ./broken-keyboard -s='Coding is fun' -k=''
3
$ ./broken-keyboard -s='The Weekly Challenge' -k=ab
2
$ ./broken-keyboard -s='Perl and Python' -k=p
1
Looking good.
With verbose mode:
$ ./broken-keyboard -v -s='Hello World' -k=d
: Words: 'hello', 'world'
: Keys: 'd'
: Typeable words: 'hello'
1
$ ./broken-keyboard -v -s='apple banana cherry' -k=ae
: Words: 'apple', 'banana', 'cherry'
: Keys: 'a', 'e'
: Typeable words:
0
$ ./broken-keyboard -v -s='Coding is fun' -k=''
: Words: 'coding', 'is', 'fun'
: Keys:
: Typeable words: 'coding', 'is', 'fun'
3
$ ./broken-keyboard -v -s='The Weekly Challenge' -k=ab
: Words: 'the', 'weekly', 'challenge'
: Keys: 'a', 'b'
: Typeable words: 'the', 'weekly'
2
$ ./broken-keyboard -v -s='Perl and Python' -k=p
: Words: 'perl', 'and', 'python'
: Keys: 'p'
: Typeable words: 'and'
1
$str
and a character in the given
string, $char
.
$char
in the given string $str and return the new string.
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"
#! /usr/bin/env raku
unit sub MAIN (:s($str) where $str.chars > 0, # [1]
:c($char) where $char.chars == 1, # [2]
:v(:$verbose));
my $index = $str.index($char); # [3]
if $index # [4]
{
my $pre = $str.substr(0, $index +1); # [5]
my $flipped = $pre.flip; # [6]
my $post = substr($index +1); # [7]
if $verbose
{
say ": Index: $index";
say ": Pre: '$pre'";
say ": Flipped: '$flipped'";
say ": Post: '$post'";
}
say $flipped ~ $post; # [8]
}
else # [9]
{
say $str; # [9a]
}
[1] A named argument for the string, with at least one character.
[2] A named argument for the single character. The examples imply letters only, and lowercase to boot, but the challenge text does not say anything about this. So I have chosen to allow anything.
[3] Use index
to look for the first occurence of the
character in the string. The return value is the index, or NIL if not found.
See docs.raku.org/routine/index for more information about index
.
Note that NIL and index 0 will both fail to trigger the if
test in [4]. The former is as intended, but the latter is a potential
problem. This can be remedied by using if $index.defined
defined
actually makes sense here.
[4] Have we found the character (at index 1 or later; as discussed above).
[5] Get the part of the string upto (and including) the character.
[6] Reverse that string with flip
. (Note that reverse
works on arrays, and will not do anything on this one-element array.)
See docs.raku.org/routine/flip for more information about flip
.
[7] Get the string after the flipped part, possibly an empty string if the flipped part gobbled up the entire string.
[8] Print the flipped part and the non-flipped remainder.
[9] No match (from [4])? Print the original string.
Note that [8] and [9] could have been combined. But then we would
have to move the declarations in [6] and [7] out of the if
-block.
Running it:
$ ./reverse-prefix -s="programming" -c=g
gorpramming
$ ./reverse-prefix -s="hello" -c=h
hello
$ ./reverse-prefix -s="abcdefghij" -c=h
hgfedcbaij
$ ./reverse-prefix -s="reverse" -c=s
srevere
$ ./reverse-prefix -s="perl" -c=r
repl
Looking good.
With verbose mode:
$ ./reverse-prefix -v -s="programming" -c=g
: Index: 3
: Pre: 'prog'
: Flipped: 'gorp'
: Post: 'ramming'
gorpramming
$ ./reverse-prefix -v -s="hello" -c=h
hello
$ ./reverse-prefix -v -s="abcdefghij" -c=h
: Index: 7
: Pre: 'abcdefgh'
: Flipped: 'hgfedcba'
: Post: 'ij'
hgfedcbaij
$ ./reverse-prefix -v -s="reverse" -c=s
: Index: 5
: Pre: 'revers'
: Flipped: 'srever'
: Post: 'e'
srevere
$ ./reverse-prefix -v -s="perl" -c=r
: Index: 2
: Pre: 'per'
: Flipped: 'rep'
: Post: 'l'
repl
And that's it.