Perl Weekly Challenge 369: string indexes

This post presents my solutions to the Perl Weekly Challenge 369.
I keep doing the Perl Weekly Challenge in order to mantain my coding skills in good shape, as well as in order to learn new things, with particular regard to Raku, a language that I love.
This week, I solved the following tasks:
The PL/Perl implementations are very similar to a pure Perl implementation, even if the PostgreSQL environment could involve some more constraints. Similarly, the PL/PgSQL implementations help me keeping my PostgreSQL programming skills in good shape.

Raku Implementations

PWC 369 - Task 1 - Raku Implementation

The first task was about transforming a given string into an hashtag like single word.

sub MAIN( Str $title ) {
    my @tags;

    for $title.lc.split( / \s+ / ) -> $word {
        next if $word !~~ / ^ <[a..z A..Z - ]>+ $ /;
        my @letters = $word.comb.Array;
        @letters[ 0 ] .= uc;
        @tags.push: @letters.join;
    }

    say '#' ~ @tags.join;
}



The idea is to collect into @tags all the words that can make up the final tag, then joining them.

PWC 369 - Task 2 - Raku Implementation

Given a string, a size and a filler, distribute the string into batches of the given size using the filler in the case the last part is not complete.

sub MAIN( Str $string is copy, Int $size, Str $filler
                                              where { $string.chars > 0 && $size > 0 && $filler.chars == 1 } ) {

    $string.say and exit if ( $size > $string.chars );

    while ( $string.chars !%% $size ) {
        $string ~= $filler;
    }

    my @parts = $string.comb.rotor( $size );
    @parts.join( ', ' ).say;

}



The idea is quite simple: $string is increased in size by adding $filler unless the size of string is a multiple of the given size. This way, I know in advance that splitting the string will result into all completed batches.

PL/Perl Implementations

PWC 369 - Task 1 - PL/Perl Implementation

Similar to the Raku implementation.

CREATE OR REPLACE FUNCTION
pwc369.task1_plperl( text )
RETURNS text
AS $CODE$

   my ( $string ) = @_;
   my @tag;


   for my $word ( split /\s+/, lc $string )  {
       next if $word !~ / [a-zA-Z\-] /x;
       my @letters = split //, $word;

       $word = uc( $letters[ 0 ] ) . join( '', @letters[ 1 .. $#letters ] );
       push @tag, $word;
   }

   return '#' . join( '', @tag );
$CODE$
LANGUAGE plperl;



PWC 369 - Task 2 - PL/Perl Implementation

Same idea of the Raku implementation.

CREATE OR REPLACE FUNCTION
pwc369.task2_plperl( text, int, text )
RETURNS SETOF text
AS $CODE$

   my ( $string, $size, $filler ) = @_;

   while ( length( $string ) % $size != 0 ) {
   	 $string .= $filler;
   }

   my $index = 0;
   my @chars = split //, $string;
   while ( $index <= length( $string ) ) {
   	 return_next( join( '', @chars[ $index .. $index + $size - 1 ] ) );
	 $index += $size;
   }

   return undef;
$CODE$
LANGUAGE plperl;



PostgreSQL Implementations

PWC 369 - Task 1 - PL/PgSQL Implementation

Iterate over single words and their content to append every good piece to the tag to return.

CREATE OR REPLACE FUNCTION
pwc369.task1_plpgsql( title text )
RETURNS text
AS $CODE$
DECLARE
	current_word text;
	current_tag text;
BEGIN
	current_tag := '#';

	for current_word in select v from regexp_split_to_table( title, '\s+' ) v loop
	    if array_length( regexp_matches( current_word, '[^a-zA-Z\-]'), 1 ) = 1 then
	       continue;
	    end if;

	    current_word := regexp_replace( current_word, '[-]', '', 'g' );
	    current_word := initcap( lower( current_word ) );
	    current_tag := current_tag || current_word;

	end loop;

	return current_tag;

END
$CODE$
LANGUAGE plpgsql;



PWC 369 - Task 2 - PL/PgSQL Implementation

Cheating, I call the PL/Perl implementation in here.

CREATE OR REPLACE FUNCTION
pwc369.task2_plpgsql( t text, s int, f text )
RETURNS SETOF text
AS $CODE$
   SELECT pwc369.task2_plperl( t, s, f );
$CODE$
LANGUAGE sql;



Java Implementations

PWC 369 - Task 1 - PostgreSQL PL/Java Implementation

Same approach as in Raku and Perl.

  public static final String task1_pljava( String title ) throws SQLException {
    logger.log( Level.INFO, "Entering pwc369.task1_pljava" );

    String tag = "#";
    String regexp = "[a-zA-Z\\-]+";
    Pattern pattern = Pattern.compile( regexp );

    for ( String word : title.split( "\\s+" ) ) {
      Matcher engine = pattern.matcher( word );

      if ( ! engine.matches() )
        continue;

      if ( word.contains( "-" ) )
        word = word.replaceAll( "-", "" );

      tag += word.substring( 0, 1 ).toUpperCase() + word.substring( 1 ).toLowerCase();
    }

    return tag;

  }


PWC 369 - Task 2 - PostgreSQL PL/Java Implementation

Similar approach as in Raku.

  public static final String[] task2_pljava( String string, int size, String filler ) throws SQLException {
    logger.log( Level.INFO, "Entering pwc369.task2_pljava" );

    List<String> result = new LinkedList<String>();

    while ( string.length() % size != 0 )
      string += filler;

    int index = 0;
    while ( index < string.length() ) {
      result.add( string.substring( index, index + size ) );
      index += size;
    }

    return (String[]) result.toArray( new String[0] );

  }


Python Implementations

PWC 369 - Task 1 - Python Implementation

Same approach as in PL/Java.

import sys
import re

# task implementation
# the return value will be printed
def task_1( args ):
    words = list( args[ 0 ].lower().split() )
    tag   = '#'
    pattern = re.compile( '[a-zA-Z\-]+' )

    for w in words:
        if not pattern.match( w ):
            continue

        while '-' in w:
            w = w.replace( '-', '' )

        tag += w[ 0 ].upper() + w[ 1: ].lower()


    return tag


# invoke the main without the command itself
if __name__ == '__main__':
    print( task_1( sys.argv[ 1: ] ) )



PWC 369 - Task 2 - Python Implementation

Use the same approach as in other implementations.

import sys

# task implementation
# the return value will be printed
def task_2( args ):
    string = args[ 0 ]
    size   = int( args[ 1 ] )
    filler = args[ 2 ]

    while len( string ) % size != 0 :
        string += filler

    parts = []
    index = 0
    while index < len( string ):
        parts.append( ''.join( list( string[ index : index + size ] ) ) )
        index += size

    return parts

# invoke the main without the command itself
if __name__ == '__main__':
    print( task_2( sys.argv[ 1: ] ) )



The article Perl Weekly Challenge 369: string indexes has been posted by Luca Ferrari on April 13, 2026