I’ve been doing the Weekly
Challenges. The
latest
involved decoding a string format and partially sorting characters.
(Note that this ends today.)
Task 1: Sort String
You are given a shuffle string, $str
.
Write a script to return the sorted string.
A string is shuffled by appending word position to each word.
Thus "Challenge3 The1 Weekly2" becomes "The Weekly Challenge".
In Perl this is relatively straightforward: build an output array, use
regexps to split word from index, and slot words into the output as
they arrive. (Yeah, I could have used an actusal sort with external
key, which would have worked if there had been gaps in the index
sequence, but this seemed easier.)
sub sortstring($a) {
my @words = split ' ', $a;
my @out = ("") x scalar @words;
foreach my $w (@words) {
$w =~ /^(.*?)([0-9]+)$/;
@out[$2 - 1] = $1;
}
return join(' ', @out);
}
Most of the other languages work more or less the same way; Lua
doesn't have true regexps built in, but does have patterns which do
basically the same thing.
But PostScript doesn't have this at all. Sooner or later I'm going to
have to write a regexp-like pattern matcher in PostScript. But not
right now.
/sortstring {
0 dict begin
( ) strsplit /words exch def
/out words length array def
words {
Split the word into an array of characters.
s2a /ws exch def
/m -1 def
/n -1 def
For each character from the end backwards,
ws reverse {
/c exch def
/n n 1 add def
Is it not a digit?
c c.isdigit not {
Tag that location and exit.
/m ws length 1 sub n sub def
exit
} if
} forall
Then extract the number…
ws m 1 add ws length m sub 1 sub getinterval a2s cvi 1 sub /ix exch def
and use it to locate the extracted string.
out ix ws 0 m 1 add getinterval a2s put
} forall
out ( ) strjoin
end
} bind def
Task 2: Reverse Word
You are given a word, $word
and a character, $char
.
Write a script to replace the substring up to and including $char
with its characters sorted alphabetically. If the $char
doesn't
exist then don't do anything.
Mostly I didn't need regexps here, and a simple find first character
in string is usually quicker. Find the split point, grab the first
tranche, sort it, append the second tranche. Ruby:
def reverseword(a, c)
mm = a.index(c)
if mm.nil?
return a
end
b = a[0, mm + 1].split("")
b.sort!()
b.concat(a[mm + 1, a.size - mm].split("") )
b.join("")
end
and near-identically in Raku:
sub reverseword($a, $c) {
with $a.index($c) -> $m {
my @aa = $a.substr(0, $m+1).comb;
@aa = sort @aa;
@aa.push($a.substr($m+1).comb.Slip);
return @aa.join('');
} else {
return $a;
}
}
Full code on
github.
Comments on this post are now closed. If you have particular grounds for adding a late comment, comment on a more recent post quoting the URL of this one.