I’ve been doing the Weekly
Challenges. The
latest
involved sliding strings and partial modifications. (Note that this
ends today.)
Task 1: Broken Keys
You have a broken keyboard which sometimes types 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.
The easy way would be regular expressions: if the given string is
"abc", the regexp /^a+b+c+$/
would have similar truthiness when
matching the typed string. But that would be boring, so I laid it out
the hard way. In Raku:
sub brokenkeys($name, $typed) {
Split strings into character arrays, and initialise index values.
my @nt = $name.comb;
my @tt = $typed.comb;
my $ni = 0;
my $ti = 0;
Loop until we're told to stop.
loop {
If the currently indexed characters don't match, bail out.
if (@nt[$ni] ne @tt[$ti]) {
return False;
}
If we've checked the last typed character, exit.
if ($ti == @tt.end) {
last;
}
If there's at least another character in the source string and it
matches the current one, step the source index forward.
if ($ni < @nt.end && @nt[$ni + 1] eq @nt[$ni]) {
$ni++;
Otherwise, if there are more characters to come in the typed string,
and the present one matches the indexed character in the source
string, step the typed index forward until one of those things isn't
true.
} else {
while ($ti < @tt.elems && @tt[$ti] eq @nt[$ni]) {
$ti++;
}
If we've run out of typed values, break out again.
if ($ti == @tt.elems) {
last;
}
Otherwise step the source index forwards.
$ni++;
}
}
If we've got to the end without a failure, this is a valid match.
True;
}
Task 2: Reverse Letters
You are given a string.
Write a script to reverse only the alphabetic characters in the
string.
PostScript:
/reverseletters {
0 dict begin
Again, build a character array.
s2a /a exch def
Build an output array, of equal length.
/vout [
a length {
32
} repeat
] def
Initialise letter stacks.
/letterslots 0 array def
/letters 0 array def
Checking each character,
a enumerate.array {
aload pop
/c exch def
/i exch def
If it's alphabetic, push position and character onto their stacks.
c c.isalpha {
/letterslots letterslots i apush.right def
/letters letters c apush.right def
} {
Otherwise, put it directly into the output list. (We could initialise
the output list as a copy of the input, but I didn't.)
vout i c put
} ifelse
} forall
Then for each letter position,
letterslots {
/i exch def
Take the letter at the top of the stack (thus in reverse order),
letters apop.right
and insert it at the noted position.
vout exch i exch put
/letters exch def
} forall
Convert the array back to a string and return it.
vout a2s
end
} bind def
Full code on
github.