Tag Division
with Raku

by Arne Sommer

Tag Division with Raku

[393] Published 15. April 2026.

This is my response to The Weekly Challenge #369.

#369.1 Valid Tag You are given a given a string caption for a video.

Write a script to generate tag for the given string caption in three steps as mentioned below:
  1. Format as camelCase
    Starting with a lower-case letter and capitalising the first letter of each subsequent word. Merge all words in the caption into a single string starting with a #.
  2. Sanitise the String
    Strip out all characters that are not English letters (a-z or A-Z).
  3. Enforce Length
    If the resulting string exceeds 100 characters, truncate it so it is exactly 100 characters long.
Example 1:
Input: $caption = "Cooking with 5 ingredients!"
Output: "#cookingWithIngredients"
Example 2:
Input: $caption = "the-last-of-the-mohicans"
Output: "#thelastofthemohicans"
Example 3:
Input: $caption = "  extra spaces here"
Output: "#extraSpacesHere"
Example 4:
Input: $caption = "iPhone 15 Pro Max Review"
Output: "#iphoneProMaxReview"
Example 5:
Input: $caption = "Ultimate 24-Hour Challenge: Living in a Smart Home \
  controlled entirely by Artificial Intelligence and Voice Commands \
  in the year 2026!"
Output: "#ultimateHourChallengeLivingInASmartHomeControlledEntirely\
  ByArtificialIntelligenceAndVoiceCommandsIn"

I have chosen to do step 2 before step 1, as the order does not really matter.

File: valid-tag
#! /usr/bin/env raku

unit sub MAIN ($caption where $caption.chars > 0,                   # [1]
               :v(:$verbose));

my $stripped = $caption.comb.grep({ /<[a..z A..Z \s]>/ }).join;     # [2]
my @words    = $stripped.words;
my $final    = "#" ~ @words.shift.lc ~ @words.map({ .tclc }).join;  # [3]

say ": English & Spaces: «$stripped»\n: Final: «$final»" if $verbose;

say $final.chars > 100 ?? $final.substr(0, 100) !! $final;          # [4]

[1] Keep the English letters (a-z and A-Z) and spaces only.

[2] Use words to get a list of words.

See docs.raku.org/routine/words for more information about words.

[3] Set up the string, starting with a '#' and the first word in lowercase (with lc). Add the rest of the words, with an uppercase initial letter and the rest in lowercase (with tclc).

See docs.raku.org/routine/lc for more information about lc.

See docs.raku.org/routine/tclc for more information about tclc.

[4] Print the result, capped to 100 characters if longer than that.

Running it:

$ ./valid-tag "Cooking with 5 ingredients!"
#cookingWithIngredients

$ ./valid-tag "the-last-of-the-mohicans"
#thelastofthemohicans

$ ./valid-tag "  extra spaces here"
#extraSpacesHere

$ ./valid-tag "iPhone 15 Pro Max Review"
#iphoneProMaxReview

$ ./valid-tag "Ultimate 24-Hour Challenge: Living in a Smart Home \
   controlled entirely by Artificial Intelligence and Voice Commands \
   in the year 2026!"
#ultimateHourChallengeLivingInASmartHomeControlledEntirelyByArtificial\
   IntelligenceAndVoiceCommandsIn

Looking good.

With verbose mode:

$ ./valid-tag -v "Cooking with 5 ingredients!"
: English & Spaces: «Cooking with  ingredients»
: Final: «#cookingWithIngredients»
#cookingWithIngredients

$ ./valid-tag -v "the-last-of-the-mohicans"
: English & Spaces: «thelastofthemohicans»
: Final: «#thelastofthemohicans»
#thelastofthemohicans

$ ./valid-tag -v "  extra spaces here"
: English & Spaces: «  extra spaces here»
: Final: «#extraSpacesHere»
#extraSpacesHere

$ ./valid-tag -v "iPhone 15 Pro Max Review"
: English & Spaces: «iPhone  Pro Max Review»
: Final: «#iphoneProMaxReview»
#iphoneProMaxReview

$ ./valid-tag -v "Ultimate 24-Hour Challenge: Living in a Smart Home \
   controlled entirely by Artificial Intelligence and Voice Commands \
   in the year 2026!"
: English & Spaces: «Ultimate Hour Challenge Living in a Smart Home \
   controlled entirely by Artificial Intelligence and Voice Commands \
   in the year »
: Final: «#ultimateHourChallengeLivingInASmartHomeControlledEntirely\
   ByArtificial\IntelligenceAndVoiceCommandsInTheYear»
#ultimateHourChallengeLivingInASmartHomeControlledEntirelyByArtificial\
   IntelligenceAndVoiceCommandsIn

#369.2 Group Division You are given a string, group size and filler character.

Write a script to divide the string into groups of given size. In the last group if the string doesn’t have enough characters remaining fill with the given filler character.

Example 1:
Input: $str = "RakuPerl", $size = 4, $filler = "*"
Output: ("Raku", "Perl")
Example 2:
Input: $str = "Python", $size = 5, $filler = "0"
Output: ("Pytho", "n0000")
Example 3:
Input: $str = "12345", $size = 3, $filler = "x"
Output: ("123", "45x")
Example 4:
Input: $str = "HelloWorld", $size = 3, $filler = "_"
Output: ("Hel", "loW", "orl", "d__")
Example 5:
Input: $str = "AI", $size = 5, $filler = "!"
Output: "AI!!!"

This task is suitable for gather/take, where we use gather to collect the parts (the groups).

File: group-division
#! /usr/bin/env raku

unit sub MAIN ($str is copy where $str.chars > 0,             # [1]
               Int $size where $size > 0,                     # [2]
	       $filler where $filler.chars == 1);             # [3]

my @output = gather                                           # [4]
{
  while $str.chars >= $size                                   # [5]
  {
    take $str.substr(0, $size);                               # [6]
    $str.substr-rw(0, $size) = "";                            # [7]
  }

  take $str ~  $filler x ($size - $str.chars) if $str.chars;  # [8]
}

say @output.join(", ");                                       # [9]

[1] A string with at least one character. Note the is copy trait, allowing us to change the string (in [7]).

See docs.raku.org/type/Parameter#method_copy for more information about is copy.

[2] The size, as a positive integer.

[3] The filler character, a single character.

[4] Collect the groups with gather.

See my Raku Gather, I Take article or docs.raku.org/language/control#gather/take for more information about gather/take.

[5] As long as we have at least one more complete group to go,

[6] return (with take) a complete group,

[7] and remove that group with substr-rw.

See docs.raku.org/routine/substr-rw for more information about substr-rw.

[8] Return a final group, padded out with the filler character, if we have any leftover characters after the loop.

[9] Print the result.

Running it:

$ ./group-division RakuPerl 4 "*"
Raku, Perl

$ ./group-division Python 5 "0"
Pytho, n0000

$ ./group-division 12345 3 x
123, 45x

$ ./group-division HelloWorld 3 "_"
Hel, loW, orl, d__

$ ./group-division AI 5 "!"
AI!!!

Looking good.

Verbose mode did not make much sense here.

And that's it.