Perl Weekly Challenge 331.

My solutions (task 1 and task 2 ) to the The Weekly Challenge - 331.

Task 1: Last Word

Submitted by: Mohammad Sajid Anwar
You are given a string.

Write a script to find the length of last word in the given string.


Example 1
Input: $str = "The Weekly Challenge"
Output: 9

Example 2
Input: $str = "   Hello   World    "
Output: 5

Example 3
Input: $str = "Let's begin the fun"
Output: 3

I make a list by splitting the input on space and print the length of the last element. I use a negative index to access arrays from the end. The result fits a half-liner.

Examples:

perl -E '
for(@ARGV){say "$_ -> ", length [split " "]->[-1]}
' "The Weekly Challenge" "   Hello   World    " "Let's begin the fun"

Results:

The Weekly Challenge -> 9
   Hello   World     -> 5
Let's begin the fun -> 3

These may fail with punctuation characters:

perl -E '
for(@ARGV){say "$_ -> ", length [split " "]->[-1]}
' "The Weekly Challenge." "   Hello   World.    " "Let's begin the fun."

Results:

The Weekly Challenge. -> 10
   Hello   World.     -> 6
Let's begin the fun. -> 4

Thus, I remove all non-word characters before computing the length:

perl -E '
for(@ARGV){say "$_ -> ", length [split " "]->[-1]=~s/\W//gr}
' "The Weekly Challenge." "   Hello   World.    " "Let's begin the fun!"

Results:

The Weekly Challenge. -> 9
   Hello   World.     -> 5
Let's begin the fun!  -> 3

The full code is:

 1  # Perl weekly challenge 331
 2  # Task 1:  Last Word
 3  #
 4  # See https://wlmb.github.io/2025/07/21/PWC331/#task-1-last-word
 5  use v5.36;
 6  die <<~"FIN" unless @ARGV;
 7      Usage: $0 S1 S2...
 8      to find the length of the last word of the strings Sn
 9      FIN
10  for(@ARGV){
11      say "$_ -> ",        # print the result
12          length           # compute the length
13          [split " "]      # separate into words
14          ->[-1]           # choose last word
15          =~s/\W//gr       # remove non-word characters
16  }

Examples:

./ch-1.pl "The Weekly Challenge" "   Hello   World    " "Let's begin the fun" \
          "The Weekly Challenge." "   Hello   World.    " "Let's begin the fun!"

Results:

The Weekly Challenge -> 9
   Hello   World     -> 5
Let's begin the fun -> 3
The Weekly Challenge. -> 9
   Hello   World.     -> 5
Let's begin the fun! -> 3

Task 2: Buddy Strings

Submitted by: Mohammad Sajid Anwar
You are given two strings, source and target.

Write a script to find out if the given strings are Buddy Strings.

If swapping of a letter in one string make them same as the other
then they are `Buddy Strings`.

Example 1
Input: $source = "fuck"
       $target = "fcuk"
Output: true

The swapping of 'u' with 'c' makes it buddy strings.

Example 2
Input: $source = "love"
       $target = "love"
Output: false

Example 3
Input: $source = "fodo"
       $target = "food"
Output: true

Example 4
Input: $source = "feed"
       $target = "feed"
Output: true

I join the source and target using the $SUBSEP ($;) special variable and let the regular expression machine do the matching. The regular expression I use is /^(.*)(.)(.*)(.)(.*)$;\1\4\3\2\5$/ . The first part matches the start ^ of the string, then an arbitrary, possibly empty string, captured as group 1 (i.e., \1), a single character (\2), another arbitrary string (\3), another single character (\4) and a final arbitrary string (\5) followed by the marker ($;) for the end of the first string. Then the second part should be the same string but with the second and fourth capture groups permuted, i.e., \1\4\3\2\5, followed by the end $ of the string. It is the job of the regular expression matcher to choose which characters go into each group when attempting the match. The result yields a longish one-liner.

Examples:

perl -E '
for my($s,$t)(@ARGV){say"$s $t -> ",($j="$s$;$t")=~/^(.*)(.)(.*)(.)(.*)$;\1\4\3\2\5$/?"T":"F"}
' fuck fcuk love love fodo food feed feed

Results:

fuck fcuk -> T
love love -> F
fodo food -> T
feed feed -> T

The full code is:

 1  # Perl weekly challenge 331
 2  # Task 2:  Buddy Strings
 3  #
 4  # See https://wlmb.github.io/2025/07/21/PWC331/#task-2-buddy-strings
 5  use v5.36;
 6  die <<~"FIN" unless @ARGV && @ARGV%2==0;
 7      Usage: $0 S1 T1 S2 T2...
 8      to find if target string Tn may be obtained from the source string Sn
 9      by a single permutation of two characters.
10      FIN
11  for my($source, $target)(@ARGV){
12      say"$source $target -> ",
13          (my $joined="$source$;$target")        # join source and target using special character
14          =~                                     # match to
15          /^                                     # start of source
16          (.*)                                   # arbitrary string (group 1)
17          (.)                                    # a single character to permute (group 2)
18          (.*)                                   # arbitrary string (group 3)
19          (.)                                    # second character to permute (group 4)
20          (.*)                                   # arbitrary string (group 5)
21          $;                                     # end of source
22          \1\4\3\2\5                             # target is source with \2 and \4 permuted
23          $                                      # end of target
24          /x
25          ?"True":"False";
26  }

Examples:

./ch-2.pl fuck fcuk love love fodo food feed feed

Results:

fuck fcuk -> True
love love -> False
fodo food -> True
feed feed -> True

Notice that I allow interchanging non-contiguous letters. If only contiguous letters may be swapped then I should remove the middle capture group and renumber the others in the regular expression above.

/;

Written on July 21, 2025