Perl Weekly Challenge 311

Upper Lower and Group Digit Sum

Published: 3 Mar 2025

Task 1: Upper Lower

You are given a string consisting of English letters only.

Write a script to convert lower case to upper and upper case to lower in the given string.

Example 1

Input: $str = "pERl" Output: "PerL"

Example 2

Input: $str = "rakU" Output: "RAKu"

Example 3

Input: $str = "PyThOn" Output: "pYtHoN"

Logic

This is a straightforward character-level transformation:

  1. Iterate over each character in the string.
  2. If the character is lowercase, convert it to uppercase.
  3. If the character is uppercase, convert it to lowercase.
  4. Return the resulting string.

In Perl, this is elegantly done with the tr/// (transliteration) operator: $str =~ tr/a-zA-Z/A-Za-z/. In Python, we use a generator expression with str.swapcase() or manual isupper()/islower() checks.

Perl Solution

ch-1.pl

#!/usr/bin/env perl use v5.38; use warnings; use feature 'signatures'; no warnings 'experimental::signatures'; ## no critic (Subroutines::ProhibitSubroutinePrototypes) use Type::Params qw(compile); use Types::Standard qw(Str); my $STR_CHECK = compile(Str); sub upper_lower ($str) { ($str) = $STR_CHECK->($str); $str =~ tr/a-zA-Z/A-Za-z/; return $str; }

Python Solution

ch-1.py

#!/usr/bin/env python3 """Upper Lower - Perl Weekly Challenge 311 task 1.""" from __future__ import annotations from collections.abc import Sequence import sys import unittest def upper_lower(text: str) -> str: """Swap case of each alphabetic character.""" return "".join(ch.lower() if ch.isupper() else ch.upper() for ch in text) class UpperLowerExamples(unittest.TestCase): """Example-based tests from the specification.""" def test_example_1(self) -> None: self.assertEqual(upper_lower("pERl"), "PerL") def test_example_2(self) -> None: self.assertEqual(upper_lower("rakU"), "RAKu") def test_example_3(self) -> None: self.assertEqual(upper_lower("PyThOn"), "pYtHoN")

Task 2: Group Digit Sum

You are given a string, $str, made up of digits, and an integer, $int, which is less than the length of the given string.

Write a script to divide the given string into consecutive groups of size $int (plus one for leftovers if any). Then sum the digits of each group, and concatenate all group sums to create a new string. If the length of the new string is less than or equal to the given integer then return the new string, otherwise continue the process.

Example 1

Input: $str = "111122333", $int = 3 Output: "359" Step 1: "111", "122", "333" => "359"

Example 2

Input: $str = "1222312", $int = 2 Output: "76" Step 1: "12", "22", "31", "2" => "3442" Step 2: "34", "42" => "76"

Example 3

Input: $str = "100012121001", $int = 4 Output: "162" Step 1: "1000", "1212", "1001" => "162"

Logic

To compute the group digit sum:

  1. Split the digit string into consecutive groups of size $int. The last group may be shorter.
  2. Sum the digits within each group.
  3. Concatenate all the sums (as strings) to form a new string.
  4. If the new string's length is less than or equal to $int, return it.
  5. Otherwise, repeat the process with the new string.

The process always terminates because each iteration reduces the string length (since the sum of digits in a group of size N is at most 9N, which has fewer digits than N for N ≥ 2).

Perl Solution

ch-2.pl

#!/usr/bin/env perl use v5.38; use warnings; use feature 'signatures'; no warnings 'experimental::signatures'; ## no critic (Subroutines::ProhibitSubroutinePrototypes) use Type::Params qw(compile); use Types::Standard qw(Int Str); my $ARGS_CHECK = compile( Str, Int ); sub _sum_digits ($chunk) { my $sum = 0; $sum += $_ for split //, $chunk; return $sum; } sub group_digit_sum ($str, $int) { ( $str, $int ) = $ARGS_CHECK->( $str, $int ); die 'Expected $int > 0' if $int <= 0; die 'Expected digits only' if $str =~ /[^0-9]/; while ( length($str) > $int ) { my @parts; for ( my $i = 0; $i < length($str); $i += $int ) { push @parts, substr( $str, $i, $int ); } $str = join '', map { _sum_digits($_) } @parts; } return $str; }

Python Solution

ch-2.py

#!/usr/bin/env python3 """Group Digit Sum - Perl Weekly Challenge 311 task 2.""" from __future__ import annotations from collections.abc import Sequence import sys import unittest def _sum_digits(chunk: str) -> int: return sum(int(ch) for ch in chunk) def group_digit_sum(text: str, size: int) -> str: """ Repeatedly sum digits in consecutive groups of ``size`` and concatenate sums. Stop once the new string length is <= ``size``. """ if size <= 0: raise ValueError("Expected size > 0") if not text.isdigit(): raise ValueError("Expected digits only") while len(text) > size: parts = [text[idx : idx + size] for idx in range(0, len(text), size)] text = "".join(str(_sum_digits(part)) for part in parts) return text class GroupDigitSumExamples(unittest.TestCase): """Example-based tests from the specification.""" def test_example_1(self) -> None: self.assertEqual(group_digit_sum("111122333", 3), "359") def test_example_2(self) -> None: self.assertEqual(group_digit_sum("1222312", 2), "76") def test_example_3(self) -> None: self.assertEqual(group_digit_sum("100012121001", 4), "162")