This is my response to The Weekly Challenge #278.
$str
.
Input: $str = "and2 Raku3 cousins5 Perl1 are4"
Output: "Perl and Raku are cousins"
Example 2:
Input: $str = "guest6 Python1 most4 the3 popular5 is2 language7"
Output: "Python is the most popular guest language"
Example 3:
Input: $str = "Challenge3 The1 Weekly2"
Output: "The Weekly Challenge"
#! /usr/bin/env raku
unit sub MAIN ($str, :v(:$verbose)); # [1]
my @new; # [2]
for $str.words -> $shuffle # [3]
{
$shuffle ~~ /(.*?)(\d+)$/; # [4]
my $word = $0; # [4a]
my $index = $1; # [4b]
say ":Word '$word' at index $index \
{ @new[$index].defined ?? 'REDEFINED' !! ''}"
if $verbose;
@new[$index] = $word; # [5]
}
say @new[1 .. *].join(" "); # [6]
#say @new.grep( *.defined ).join(" "); # [7]
[1] A string, without any constraints.
[2] The new (sorted) list of words will end up here.
[3] Iterate over the words in the sentence.
See docs.raku.org/routine/words for more information about words
.
[4] Grab anything before one or more trailing digits (note the non-greedy
pattern .*?
so that all the trailing digits are gobbled up by the
greedy digit pattern), and save it [4a]. Then save that number [4b].
[5] Insert the word at the given position (index) in the new array.
[6] Print the content of the array, excluding the undefined value with index zero, with spaces between them.
[7] I'll get back to this later.
Running it:
$ ./sort-string "and2 Raku3 cousins5 Perl1 are4"
Perl and Raku are cousins
$ ./sort-string "guest6 Python1 most4 the3 popular5 is2 language7"
Python is the most popular guest language
$ ./sort-string "Challenge3 The1 Weekly2"
The Weekly Challenge
Looking good.
With verbose mode:
$ ./sort-string -v "and2 Raku3 cousins5 Perl1 are4"
:Word 'and' at index 2
:Word 'Raku' at index 3
:Word 'cousins' at index 5
:Word 'Perl' at index 1
:Word 'are' at index 4
Perl and Raku are cousins
$ ./sort-string -v "guest6 Python1 most4 the3 popular5 is2 language7"
:Word 'guest' at index 6
:Word 'Python' at index 1
:Word 'most' at index 4
:Word 'the' at index 3
:Word 'popular' at index 5
:Word 'is' at index 2
:Word 'language' at index 7
Python is the most popular guest language
$ ./sort-string -v "Challenge3 The1 Weekly2"
:Word 'Challenge' at index 3
:Word 'The' at index 1
:Word 'Weekly' at index 2
The Weekly Challenge
Let us have a go at garbage in:
$ ./sort-string -v "Challenge4 The1 Weekly2"
:Word 'Challenge' at index 4
:Word 'The' at index 1
:Word 'Weekly' at index 2
The Weekly
That was perhaps not obvious. The [1 .. *]
array slice stops
at the first undefined value, i.e. @new[3]
.
The alternate version in [7] will ignore (skip) any undefined entries, and print all the words. You may prefer [6], as in «garbage in, constipation out».
Reuse of word positions is not prevented, but verbose mode will notify you:
$ ./sort-string -v "and2 Raku3 cousins5 Perl1 are4 Ronny3"
:Word 'and' at index 2
:Word 'Raku' at index 3
:Word 'cousins' at index 5
:Word 'Perl' at index 1
:Word 'are' at index 4
:Word 'Ronny' at index 3 REDEFINED
Perl and Ronny are cousins
$word
and a character, $char
.
$char
with its characters sorted alphabetically. If the $char
doesn't
exist then DON'T do anything.
Input: $str = "challenge", $char = "e"
Ouput: "acehllnge"
Example 2:
Input: $str = "programming", $char = "a"
Ouput: "agoprrmming"
Example 3:
Input: $str = "champion", $char = "b"
Ouput: "champion"
Neither the challenge nor the examples say what to do if the character uccurs more than once. I have decided to stop after the very first one.
File: reverse-word
#! /usr/bin/env raku
unit sub MAIN ($word is copy, $char where $char.chars == 1); # [1]
$word = $0.comb.sort.join ~ $1 if $word ~~ /(.*? $char) (.*)/; # [2]
say $word; # [3]
[1] The word, followed by a single character. Note the
is copy
trait, so that we can change the variable in [2].
See docs.raku.org/type/Parameter#method_copy for more information about is copy
.
[2] First the regexp (the second half): Here we look for the
specified character, in the non-greedy pattern .*?
. This will match
up to and including the first occurence of the character. The greedy
pattern .*
will gobble up the rest of the string. The if
executes the first part (the assignment) if we did get a match. The
assignment is the first part sorted alphabetically (or rather by Unicode
codepoint value) by splitting the string into separate characters
(comb
), sorting them (sort
) and gluing them together again
join
). Then we slap on the second part.
See docs.raku.org/routine/comb for more information about comb
.
[3] Print the result.
Running it:
$ ./reverse-word challenge e
acehllnge
$ ./reverse-word programming a
agoprrmming
$ ./reverse-word champion b
champion
./
Looking good.
Some examples where the character occurs more than once:
$ ./reverse-word programming r
programming
$ ./reverse-word language a
alnguage
$ ./reverse-word challenge l
achllenge
And that's it.