21 March 2025 | Challenge 313 |
Broken Down Letters
Task 1: Broken Keys
Submitted by: Mohammad Sajid Anwar
You have a broken keyboard which sometimes type a character more than once.
You are given a string and actual typed string.
Write a script to find out if the actual typed string is meant for the given string.
Example 1
Input: $name = "perl", $typed = "perrrl"
Output: true
Here "r" is pressed 3 times instead of 1 time.
Example 2
Input: $name = "raku", $typed = "rrakuuuu"
Output: true
Example 3
Input: $name = "python", $typed = "perl"
Output: false
Example 4
Input: $name = "coffeescript", $typed = "cofffeescccript"
Output: true
Solution
The solution to this task were a bit more complex if the broken keyboard typed the keys individually a fixed number of times. But from example 4 we see that the repetition factor is random.
Therefore we just need to check if every character from $name
occurs one or more times in $typed
,
where regex meta characters need to be quoted.
This fits into a single regex:
use strict;
use warnings;
use experimental 'prototypes'
sub broken_keys ($name, $typed) {
$typed =~ /^(??{$name =~ s#.#\Q$&\E+#gr})$/;
}
See the full solution to task 1.
Task 2: Reverse Letters
Submitted by: Mohammad Sajid Anwar
You are given a string.
Write a script to reverse only the alphabetic characters in the string.
Example 1
Input: $str = "p-er?l"
Output: "l-re?p"
Example 2
Input: $str = "wee-k!L-y"
Output: "yLk-e!e-w"
Example 3
Input: $str = "_c-!h_all-en!g_e"
Output: "_e-!g_nel-la!h_c"
Solution
In some tasks, when alphabetic was restricted to English (or Latin) letters, I tried to extend the task to a more general concept of letters. Here we have no restriction to English letters and therefore as a matter of course I’ll not make such a restriction.
One obvious characterization of a character as letter is the Unicode
“General Category: Letter”
(see also: perluniprops).
However, if we’d split the given string into characters, this would cause unwanted effects.
Consider the string "a\N{COMBINING DIAERESIS},o&u"
that is printed as 'ä,o&u'
.
Here \N{COMBINING DIAERESIS}
is not a letter and would be kept in its position producing the reversed output "u\N{COMBINING DIAERESIS},o&a"
or 'ü,o&a'
whereas the desired result would be 'u,o&ä'
Therefore we split the string into grapheme clusters and regard a letter as a grapheme cluster containing a character having the letter property.
use strict;
use warnings;
use List::MoreUtils 'indexes';
sub reverse_letters {
my @s = shift =~ /\X/g;
my @li = indexes {/\p{L}/} @s;
@s[@li] = @s[reverse @li];
join '', @s;
}
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.