Perl Weekly Challenge 253: Split Strings

These are some answers to the Week 253, Task 1, of the Perl Weekly Challenge organized by Mohammad S. Anwar.

Spoiler Alert: This weekly challenge deadline is due in a few days from now (on January 28, 2024 at 23:59). This blog post provides some solutions to this challenge. Please don’t read on if you intend to complete the challenge on your own.

Task 1: Split Strings

You are given an array of strings and a character separator.

Write a script to return all words separated by the given character excluding empty string.

Example 1

Input: @words = ("one.two.three","four.five","six")
       $separator = "."
Output: "one","two","three","four","five","six"

Example 2

Input: @words = ("$perl$$", "$$raku$")
       $separator = "$"
Output: "perl","raku"

Split Strings in Raku

Since we are passing two very different arguments to our split-strings subroutine, a single character and an array of strings, I thought it was a good opportunity to brush up my knowledge of named arguments to a subroutine. The arguments are supplied at the subroutine call as a list of pairs using the pair constructor syntax. In the subroutine signature, the parameters are retrieved with the so-called colon-pair syntax.

Otherwise, this is quite simple. We're using a grep to remove empty strings from the result.

sub split-strings (:$sep, :@strings) {
    my @result = grep { /\w+/ }, flat  
        map { split $sep, $_ }, @strings;
    return @result;
}


my @tests = {
    'separator' => '.',  
    'string' => ("one.two.three","four.five","six")
    }, {
    'separator' => '$', 
    'string' => ('$perl$$', '$$raku$')};
for @tests -> %test {
    printf "%-30s => ",  %test<string>;
    say split-strings(sep => %test<separator>, 
                      strings => %test<string>);
}

This program displays the following output:

$ raku  ./split-strings.raku
one.two.three four.five six    => [one two three four five six]
$perl$$ $$raku$                => [perl raku]

Split Strings in Perl

This is a port to Perl of the above Raku program, except that we use here normal positional parameters. Please loop at the previous section if you need further explanations. Note that we use the quotemeta operator to make sure that the separator will be properly backslashed (to transform the separator string into a regex).

use strict;
use warnings;
use feature 'say';

sub split_strings {
    my ($sep, @strings) = @_;
    $sep = quotemeta $sep;
    my @result = grep { /\w+/ }  
        map { split $sep, $_ } @strings;
    return @result;
}

my @tests = ( [ '.', ["one.two.three","four.five","six"] ],
              [ '$', ['$perl$$', '$$raku$'] ] );
for my $test (@tests) {
    printf "%-30s => ",  "@{$test->[1]}";
    say join " ", split_strings $test->[0], @{$test->[1]};
}

This program displays the following output:

$ perl ./split-strings.pl
one.two.three four.five six    => one two three four five six
$perl$$ $$raku$                => perl raku

Wrapping up

The next week Perl Weekly Challenge will start soon. If you want to participate in this challenge, please check https://perlweeklychallenge.org/ and make sure you answer the challenge before 23:59 BST (British summer time) on February 4, 2024. And, please, also spread the word about the Perl Weekly Challenge if you can.

Leave a comment

About laurent_r

user-pic I am the author of the "Think Perl 6" book (O'Reilly, 2017) and I blog about the Perl 5 and Raku programming languages.