Broken letters

Weekly Challenge 313 Each week Mohammad S. Anwar sends out The Weekly Challenge, a chance for all of us to come up with solutions to two weekly tasks. My solutions are written in Python first, and then converted to Perl. It's a great way for us all to practice some coding. Challenge, My solutions Task 1: Broken Keys Task 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. My solution This is a two liner for both the Perl and Python solutions. I can use a regular expression to see if the typed value contains one or more of each character in the name variable. The thing that needs to be handled is escaping any characters that have special meaning in a regular expression. Thankfully Perl has quotemeta and Python has re.escape method to handle this. The entire regular expressions starts with ^ to signify the start of the string. It then has each letter (escaped if required) followed by a + character, which means one or more of that letter. The regular expression ends with a $ for the end of the string. Python def broken_keys(name: str, typed: str) -> bool: r = '^' + '+'.join(map(re.escape, name)) + '+$' return re.search(r, typed) Perl sub main ( $name, $typed ) { my $r = '^' . join( '+', map { quotemeta } split //, $name ) . '+$'; say $typed =~ $r ? 'true' : 'false'; } Examples $ ./ch-1.py perl perrrl True $ ./ch-1.py raku rrakuuuu True $ ./ch-1.py python perl False $ ./ch-1.py coffeescript cofffeescccript True Task 2: Reverse Letters Task You are given a string. Write a script to reverse only the alphabetic characters in the string. My solution Let's start with discussion about my Perl solution. This also is a two liner. The first line extracts all the letters from the string, and stores it in the array called @letters. The second line replaces all the letters by calling pop(@letters) each time a letter is found. The regular expression has three modifiers: i is for a case insensitive search g is for global (replace all occurrences) e will evaluate the right side as an expression. sub main ($str) { my @letters = grep { /[a-z]/i } split //, $str; $str =~ s/[a-z]/pop(@letters)/ige; say $str; } I was thinking that my Python solution would be use the same logic. But it turns out that letters.pop() is only computed once, and thus all the letters are replaced with the last letter found. I'm not entirely sure the reasons why, and given that this isn't my day job, I'm not going to spend too much time on finding out why :) My Python solution starts out the same by extracting all the letters found into list called letters. def reversed_letters(typed: str) -> str: letters = [s for s in typed if s.isalpha()] I then go though each character in the original string. If it is a letter, I take the last letter from the letters list and add it to the new_string variable. If it isn't, I add the character to the new_string variable. new_string = '' for char in typed: if char.isalpha(): new_string += letters.pop() else: new_string += char return new_string One thing to note is the Perl solution will only match the 26 letters of the English alphabet. The Python solution will match characters of any alphabet. Examples The second and third examples are surrounded in quotes as the exclamation mark (!) has special meaning in bash. $ ./ch-2.py p-er?l l-re?p $ ./ch-2.py 'wee-k!L-y' yLk-e!e-w $ ./ch-2.py '_c-!h_all-en!g_e' _e-!g_nel-la!h_c

Mar 23, 2025 - 13:21
 0
Broken letters

Weekly Challenge 313

Each week Mohammad S. Anwar sends out The Weekly Challenge, a chance for all of us to come up with solutions to two weekly tasks. My solutions are written in Python first, and then converted to Perl. It's a great way for us all to practice some coding.

Challenge, My solutions

Task 1: Broken Keys

Task

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.

My solution

This is a two liner for both the Perl and Python solutions. I can use a regular expression to see if the typed value contains one or more of each character in the name variable.

The thing that needs to be handled is escaping any characters that have special meaning in a regular expression. Thankfully Perl has quotemeta and Python has re.escape method to handle this.

The entire regular expressions starts with ^ to signify the start of the string. It then has each letter (escaped if required) followed by a + character, which means one or more of that letter. The regular expression ends with a $ for the end of the string.

Python

def broken_keys(name: str, typed: str) -> bool:
    r = '^' + '+'.join(map(re.escape, name)) + '+$'
    return re.search(r, typed)

Perl

sub main ( $name, $typed ) {
    my $r = '^' . join( '+', map { quotemeta } split //, $name ) . '+$';
    say $typed =~ $r ? 'true' : 'false';
}

Examples

$ ./ch-1.py perl perrrl
True

$ ./ch-1.py raku rrakuuuu
True

$ ./ch-1.py python perl
False

$ ./ch-1.py coffeescript cofffeescccript
True

Task 2: Reverse Letters

Task

You are given a string.

Write a script to reverse only the alphabetic characters in the string.

My solution

Let's start with discussion about my Perl solution. This also is a two liner. The first line extracts all the letters from the string, and stores it in the array called @letters. The second line replaces all the letters by calling pop(@letters) each time a letter is found.

The regular expression has three modifiers:

  • i is for a case insensitive search
  • g is for global (replace all occurrences)
  • e will evaluate the right side as an expression.
sub main ($str) {
    my @letters    = grep { /[a-z]/i } split //, $str;
    $str =~ s/[a-z]/pop(@letters)/ige;
    say $str;
}

I was thinking that my Python solution would be use the same logic. But it turns out that letters.pop() is only computed once, and thus all the letters are replaced with the last letter found.

I'm not entirely sure the reasons why, and given that this isn't my day job, I'm not going to spend too much time on finding out why :)

My Python solution starts out the same by extracting all the letters found into list called letters.

def reversed_letters(typed: str) -> str:
    letters = [s for s in typed if s.isalpha()]

I then go though each character in the original string. If it is a letter, I take the last letter from the letters list and add it to the new_string variable. If it isn't, I add the character to the new_string variable.

    new_string = ''
    for char in typed:
        if char.isalpha():
            new_string += letters.pop()
        else:
            new_string += char

    return new_string

One thing to note is the Perl solution will only match the 26 letters of the English alphabet. The Python solution will match characters of any alphabet.

Examples

The second and third examples are surrounded in quotes as the exclamation mark (!) has special meaning in bash.

$ ./ch-2.py p-er?l
l-re?p

$ ./ch-2.py 'wee-k!L-y'
yLk-e!e-w

$ ./ch-2.py '_c-!h_all-en!g_e'
_e-!g_nel-la!h_c