Peter’s blog ✴ Week 329 ✴ 7 July 2025

THE WEEKLY CHALLENGE
Fun with strings

The Perl Camel

Task 2

Nice string

You are given a string made up of lower and upper case English letters only. Write a script to return the longest substring of the given string which is nice.

A string is nice if, for every letter of the alphabet that the string contains, it appears both in uppercase and lowercase.

Examples


Example 1
Input: $str = 'YaaAho'
Output: 'aaA'

Example 2
Input: $str = 'cC'
Output: 'cC'

Example 3
Input: $str = 'A'
Output: ''
No nice string found.

Analysis

I chose to approach this challenge in what could be called the systematic - or boring - way.

I loop over the possible starting characters, and then over the possible lengths of substrings which are larger than the nicest substring found so far. I then check each of these for niceness, and if one is nice, I save it as the new nicest.

I chose to pull out the test for a substring being nice into a separate subroutine is_nice() mainly to make the code clearer to read.

Perl Weekly’s review

from PW issue 729

The post does a great job of highlighting ambiguities in specifications. It identifies potential edge cases (a9a09a) and makes reasonable assumptions while also pointing out how easily such details can be overlooked or underspecified.

Try it 

Try running the script with any input:



example: chopCHOPwood

Script


#!/usr/bin/perl

# Blog: http://ccgi.campbellsmiths.force9.co.uk/challenge

use v5.26;    # The Weekly Challenge - 2025-07-07
use utf8;     # Week 329 - task 2 - Nice string
use warnings; # Peter Campbell Smith
binmode STDOUT, ':utf8';
use Encode;

nice_string('YaaAho');
nice_string('cC');
nice_string('A');
nice_string('ABCDEedcbaZABCDEedcbaa');

# longer example
my (@chars, $string);
@chars = (('A' .. 'I'),('a' .. 'i'));
$string .= $chars[int(rand(18))] for 0 .. 50;
nice_string($string);

sub nice_string {
    
    my ($string, $c, $best, $longest, $s, $t, $try);
    
    # initialise
    $string = shift;
    $c = length($string);
    $best = '';
    $longest = 0;
    
    # loop over starting points
    for $s (0 .. $c - 2) {
        
        # loop up to remaining length
        for $t (0 .. $c - $s) {
            next unless $t >= $longest;
            $try = substr($string, $s, $t);
            
            # nicest so far?
            if (is_nice($try)) { 
                $best = $try;
                $longest = $t;
            }
        }
    }
    
    say qq[\nInput:  '$string'];
    say qq[Output: '$best'];
}

sub is_nice {
    
    my ($string, @chars, $c, $C);
    
    # initialise
    $string = shift;
    @chars = split('', $string);
    
    # check for nicety
    for $c (@chars) {
        $C = $c gt 'Z' ? uc($c) : lc($c);
        return 0 unless $string =~ m|$C|;
    }
    return 1;
}

23 lines of code

Output from script


Input:  'YaaAho'
Output: 'aaA'

Input:  'cC'
Output: 'cC'

Input:  'A'
Output: ''

Input:  'ABCDEedcbaZABCDEedcbaa'
Output: 'ABCDEedcbaa'

Input:  'IDbaDfiIDCDFHeEdHeFbGEGgbeBHdCAfBHbFfHIgCfiifAAI'
Output: 'bGEGgbeB'

 

Any content of this website which has been created by Peter Campbell Smith is in the public domain