Perl Weekly Challenge 330: crunching words
This post presents my solutions to the Perl Weekly Challenge 330.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:
- PWC 330 - Task 1 - Raku
- PWC 330 - Task 2 - Raku
- PWC 330 - Task 1 in PostgreSQL PL/Perl
- PWC 330 - Task 2 in PostgreSQL PL/Perl
- PWC 330 - Task 1 in PostgreSQL PL/PgSQL
- PWC 330 - Task 2 in PostgreSQL PL/PgSQL
- PWC 330 - Task 1 in PL/Java
- PWC 330 - Task 2 in PL/Java
- PWC 330 - Task 1 in Python
- PWC 330 - Task 2 in Python
Raku Implementations
PWC 330 - Task 1 - Raku Implementation
The first task was about to trim a given string so that each digit is removed according to the letter it has on the left.sub MAIN( Str $string is copy
where { $string ~~ / ^ <[a .. z 0 .. 9 ]>+ $ / } ) {
while ( $string ~~ / (<[a .. z]>) (<[ 0 .. 9 ]>) / ) {
$string .= subst( / (<[a .. z]>) (<[ 0 .. 9 ]>) /, '' );
}
$string.say;
}
The idea is to loop while a regular expression that matches a letter followed by a number matches, and substitute the capture with nothing.
PWC 330 - Task 2 - Raku Implementation
Title case only words longer than three chars, and lower case all the rest.sub MAIN( Str $sentence is copy ) {
my @parts;
for $sentence.split( ' ' ) {
@parts.push: $_.Str.chars >= 3 ?? $_.tc !! $_.lc;
}
@parts.join( ' ' ).say;
}
I iterate over all the words and append the result, converted into
tc
(titlecase) or lc
(lowercase) according to its length, so that I can rejoin
the words.
PL/Perl Implementations
PWC 330 - Task 1 - PL/Perl Implementation
Very similar to the Raku implementation.CREATE OR REPLACE FUNCTION
pwc330.task1_plperl( text )
RETURNS text
AS $CODE$
my ( $string ) = @_;
die "Invalid string" unless( $string =~ / ^ [a-z0-9]+ $ /x );
while ( $string =~ / [a-z] [0-9] /x ) {
$string =~ s/ ([a-z]) ([0-9]) //x;
}
return $string;
$CODE$
LANGUAGE plperl;
PWC 330 - Task 2 - PL/Perl Implementation
Similar to the Raku implementation, uses an array to keep track of the words and re-joins them at the end.CREATE OR REPLACE FUNCTION
pwc330.task2_plperl( text )
RETURNS text
AS $CODE$
my ( $text ) = @_;
die "Invalid argument" unless( length( $text ) > 2 );
my @parts;
for ( split( ' ', $text ) ) {
push @parts, length( $_ ) >= 3 ? ucfirst( $_ ) : lc( $_ );
}
return join( ' ', @parts );
$CODE$
LANGUAGE plperl;
PostgreSQL Implementations
PWC 330 - Task 1 - PL/PgSQL Implementation
The same implementation as in Raku, except that the strings
is substituted at every iteration.
CREATE OR REPLACE FUNCTION
pwc330.task1_plpgsql( s text )
RETURNS text
AS $CODE$
DECLARE
BEGIN
WHILE regexp_match( s, '[a-z][0-9]' ) IS NOT NULL LOOP
s := regexp_replace( s, '([a-z])([0-9])', '' );
END LOOP;
RETURN s;
END
$CODE$
LANGUAGE plpgsql;
PWC 330 - Task 2 - PL/PgSQL Implementation
Every word is cased appropriately, and then returned as part of the set of text to return.CREATE OR REPLACE FUNCTION
pwc330.task2_plpgsql( s text )
RETURNS SETOF text
AS $CODE$
DECLARE
current text;
BEGIN
FOR current IN SELECT v FROM regexp_split_to_table( s, ' ' ) v LOOP
IF length( current ) >= 3 THEN
current := upper( current );
ELSE
current := lower( current );
END IF;
RETURN NEXT current;
END LOOP;
RETURN;
END
$CODE$
LANGUAGE plpgsql;
Java Implementations
PWC 330 - Task 1 - PostgreSQL PL/Java Implementation
A not prefect solution: it iterates over the matches and substitutes them with nothing, then recompile the match and iterate again. public static final String task1_pljava( String string ) throws SQLException {
logger.log( Level.INFO, "Entering pwc330.task1_pljava" );
Pattern regexp = Pattern.compile( "([a-z])([0-9])" );
Matcher engine = regexp.matcher( string );
while ( engine.find() ) {
string = string.replaceAll( engine.group( 1 ) + engine.group( 2 ), "" );
engine = regexp.matcher( string );
}
return string;
}
PWC 330 - Task 2 - PostgreSQL PL/Java Implementation
A Stream API based solution. public static final String task2_pljava( String string ) throws SQLException {
logger.log( Level.INFO, "Entering pwc330.task2_pljava" );
return Arrays
.stream( string.split( " " ) )
.map( word -> word.length() <= 2
? word.toLowerCase()
: Character.toTitleCase( word.charAt(0) ) + word.substring( 1 ).toLowerCase() )
.collect( Collectors.joining( " " ) );
}
I use
stream
to split
the string into words, then to ‘map into a variable
word that is tested for its length and converted to the appropriate case, last all the stuff is
collect`ed with spaces.
Python Implementations
PWC 330 - Task 1 - Python Implementation
Basically, the same implementation as in other tasks.import sys
import re
# task implementation
# the return value will be printed
def task_1( args ):
string = args[ 0 ]
regexp = re.compile( r'[a-z][0-9]' )
while regexp.search( string ) is not None:
string = re.sub( r'[a-z][0-9]', '', string )
return string
# invoke the main without the command itself
if __name__ == '__main__':
print( task_1( sys.argv[ 1: ] ) )
PWC 330 - Task 2 - Python Implementation
No regular expressions in here, since it does suffice to iterate over the whole list of arguments and case them according.import sys
# task implementation
# the return value will be printed
def task_2( args ):
parts = []
for current in args :
if len( current ) >= 3 :
current = current.title()
else:
current = current.lower()
parts.append( current )
return ' '.join( parts )
# invoke the main without the command itself
if __name__ == '__main__':
print( task_2( sys.argv[ 1: ] ) )