The Bear's Den

Enter at your own risk

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.