Endings, Elephants and Explanations : Raku Weekly Challenge : Week 330

Week 330 : 2025-07-14

Always read between the lines : Part 1

I went through a couple of iterations for this weeks challenge but it's pretty simple. Still lets get through it. Firstly we are given a string made of lowercase letters and number so we'll define that as a subset for validation purposes.


subset ValidInput of Str where /^ <[a..z 0..9]>+ $/;
      

I love Raku's typing system, in the past I've described it as "A strongly typed system with sensible defaults". At first it looks like there's no typing, you can created functions and methods without any typing required and it just works. What you don't see is that under the hood it's just using the default Any type. But subsets are another great part because you can do very powerful things with them especially when combined with multi dispatch. More on that later but first I'm going to add some tests. Which is using multi dispatch to run the tests from the command line.


multi sub MAIN(:t(:$test)) is hidden-from-USAGE {
    use Test;
    is clear-digits("cab12"),"c";
    is clear-digits("xy99"), "";
    is clear-digits("pa1erl"), "perl";
    is clear-digits("1234a"), "a";
    is clear-digits("a123"),"";
    done-testing;
}
      

Here we're testing all the examples from the challenge and also a couple of extra to deal with the digits which don't have a letter to their left. So lets implement clear-digits.


sub clear-digits(ValidInput $str is copy) {
    loop-strip( $str, / \D?\d / );
}
      

...

Ok so what happened was I had two loops. One to remove a non digit followed by a digit and then when that was done we removed all the digits at the start of the string. Then I realised I was duplicating code so I wrote loop-strip which is below that takes a string and a regex and keeps removing the match from the string until it stops changing.

Then I realised that we could just match a digit with zero or one non digit before it... So I didn't need two loops, but I was at the "Ship It" stage of Monday morning so kept loop-strip in.


sub loop-strip( $str is copy, $regex ) {
    my $new;
    repeat {
        $new = $str;
        $str ~~ s/ $regex //;
    } while $new ne $str;
    return $new;
}         
      

With the we then just add the MAIN function and we're done.


#|( Given a string of letters and number
remove all the numbers and the left most
letter found before each one)
multi sub MAIN(
    ValidInput $str #= String made of letters and numbers
) {
    clear-digits($str).say;
}
      

The Writing is on the Wall

So the code for this challenge is pretty simple, firstly we'll define words as strings of upper and lower case letters and sentences as lists of words joined by single spaces.


subset ValidWord of Str where /^ <[a..z A..Z]>+ $/;
subset ValidSentence of Str where { all($_.split(" ")) ~~ ValidWord };     
      

Then with that we want to take our sentence, split it on spaces, make each part lowercase and then if it's longer than 2 letters make it title case. Then join again with spaces.


sub title-caps(ValidSentence $str is copy) {
    $str
    .split(" ")
    .map(*.lc)
    .map( -> $a { $a.codes > 2 ?? $a.tc !! $a } )
    .join(" ");
}
      

So with that in place we want our main function and here we use the power of multi dispatch and typing to handle the case where you call the script with a single string or if you call it with multiple string arguments.



#|(Accepts a string made of
upper and lower case letters. Outputs the 
sentence nicely capitalised)
multi sub MAIN(
    ValidSentence $str #= Sentence made or letters in both cases
) {
    title-caps($str).say;
}

#|(Accepts a list of strings made of
upper and lower case letters. Outputs the 
sentence nicely capitalised
)
multi sub MAIN(
    *@words where all(@words) ~~ ValidWord #= List of words
) {
    title-caps(@words.join(" ")).say;
}         
      

And there we are for another weeks challenge. I hope you've enjoy this little bit of rambling. Feel free to message me on Threads, Bluesky, Mastodon or Reddit.... Heck I even post to some of them sometimes.