Perl Weekly Challenge 385.

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

Task 1: Uncommon Words

Submitted by: Mohammad Sajid Anwar
You are given two sentences.

Write a script to return list of all uncommon words, order
is not important.

Example 1
Input: $sentence1 = "apple banana apple"
       $sentence2 = "banana orange"
Output: ("orange")

Example 2
Input: $sentence1 = "cat dog"
       $sentence2 = "bird fish"
Output: ("cat", "dog", "bird", "fish")

Example 3
Input: $sentence1 = "the quick brown fox"
       $sentence2 = "the quick"
Output: ("brown", "fox")

Example 4
Input: $sentence1 = "hello"
       $sentence2 = "hello"
Output: ()

Example 5
Input: $sentence1 = "blue blue red"
       $sentence2 = "red green green yellow"
Output: ("yellow")


I can use hashes to count the words in both sets. Uncommon words would have a count of 1. The code fits a 2-liner.

Examples:

perl -E '
for my($l, $m)(@ARGV){my%h;++$h{$_}for split" ","$l $m";@o=
grep{$h{$_}==1}keys %h;say "$l; $m -> @o"}
' "apple banana apple" "banana orange" "cat dog" "bird fish" \
  "the quick brown fox" "the quick" "hello" "hello" \
  "blue blue red" "red green green yellow"

Results:

apple banana apple; banana orange -> orange
cat dog; bird fish -> fish bird cat dog
the quick brown fox; the quick -> fox brown
hello; hello ->
blue blue red; red green green yellow -> yellow

The full code is

 1  # Perl weekly challenge 385
 2  # Task 1:  Uncommon Words
 3  #
 4  # See https://wlmb.github.io/2026/08/03/PWC385/#task-1-uncommon-words
 5  use v5.36;
 6  die <<~"FIN" unless @ARGV && @ARGV %2 == 0;
 7      Usage: $0 X0 Y0 X1 Y1...
 8      to find non-repeated words in the strings Xn and Yn.
 9      FIN
10  for my($sentence1, $sentence2)(@ARGV){
11      my %count;
12      ++$count{$_} for split" ","$sentence1 $sentence2";
13      my @out = grep{$count{$_}==1} keys %count;
14      say "$sentence1; $sentence2 -> (@out)";
15  }

Example:

./ch-1.pl "apple banana apple" "banana orange" "cat dog" "bird fish" \
          "the quick brown fox" "the quick" "hello" "hello" \
          "blue blue red" "red green green yellow"

Task 2: Outermost Parentheses

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

Write a script to return the string after removing the outermost parentheses of every primitive string in the primitive decomposition of the given string.

Example 1 Input: $str = “()()()” Output: “”

Primitive Decomposition: “()” + “()” + “()”

Example 2 Input: $str = “(((())))” Output: “((()))”

Primitive Decomposition: “(((())))”

Example 3 Input: $str = “(()())(())” Output: “()()()”

Primitive Decomposition: “(()())” + “(())”

Example 4 Input: $str = “()((()))()” Output: “(())”

Primitive Decomposition: “()” + “((()))” + “()”

Example 5 Input: $str = “(()(()))(()())” Output: “()(())()()”

Primitive Decomposition: “(()(()))” + “(()())” #+endexample

I make a Schwartzian transform to count the the depth of every parenthesis and remove those at depth 0. The results fits a 2-liner.

Examples:

perl -E '
for(@ARGV){@x=split"",$_;$c=0;say"$_ -> ",map{$_->[0]}grep
{$_->[1]>0}map{/\(/?[$_,$c++]:[$_,--$c]} split "",$_}
' "()()()" "(((())))" "(()())(())" "()((()))()" "(()(()))(()())"

Results:

()()() ->
(((()))) -> ((()))
(()())(()) -> ()()()
()((()))() -> (())
(()(()))(()()) -> ()(())()()

This worked as some hidden assumptions held, i.e., the count was never negative and no characters were present but opening and closing parenthesis.

A more robust solution may be obtained by using Text::Balanced= to extract balanced parenthesized sub-expressions, though the solution is much more complex.

 1  # Perl weekly challenge 385
 2  # Task 2:  Outermost Parentheses
 3  #
 4  # See https://wlmb.github.io/2026/08/03/PWC385/#task-2-outermost-parentheses
 5  use v5.36;
 6  use Text::Balanced qw(extract_bracketed);
 7  die <<~"FIN" unless @ARGV;
 8      Usage: $0 S0 S1...
 9      to extract the string Sn after removing the
10      outermost parentheses of every primitive string in the
11      primitive decomposition of the given string.
12      FIN
13  for(@ARGV){
14      my $remaining=$_;
15      my ($extracted, $before);
16      my $out="";
17      while(1){
18          ($extracted, $remaining, $before)=extract_bracketed($remaining,"()", "[^\(]*");
19          if(!defined $extracted){
20              $out.="(", next if $remaining=~s/^\(//; #skip opening parenthesis and try again
21              $out.=$remaining;
22              last;
23          }
24          $extracted=~s/^\(|\)$//g;
25          $out.="$before$extracted";
26      }
27      say "'$_' -> \"$out\"";
28  }
29  

Examples:

./ch-2.pl "()()()" "(((())))" "(()())(())"  "()((()))()" "(()(()))(()())"

Results:

'()()()' -> ""
'(((())))' -> "((()))"
'(()())(())' -> "()()()"
'()((()))()' -> "(())"
'(()(()))(()())' -> "()(())()()"

Unbalanced examples:

./ch-2.pl "())" "(()" "(()(())(())"

Results:

'())' -> ")"
'(()' -> "("
'(()(())(())' -> "(()()"

/;

Written on August 3, 2026