Peter’s blog ✴ Week 374 ✴ 18 May 2026

THE WEEKLY CHALLENGE
Lots of repetition

The Perl Camel

Task 1

Count vowel

You are given a string. Write a script to return all possible vowel substrings in the given string. A vowel substring is a substring that only consists of vowels and has all five vowels present in it.

Examples


Example 1
Input: $str = 'aeiou'
Output: ('aeiou')

Example 2
Input: $str = 'aaeeeiioouu'
Output: ('aaeeeiioou', 'aaeeeiioouu', 'aeeeiioou',
   'aeeeiioouu')

Example 3
Input: $str = 'aeiouuaxaeiou'
Output: ('aeiou', 'aeiou', 'eiouua', 'aeiouu', 'aeiouua')

Example 4
Input: $str = 'uaeiou'
Output: ('aeiou', 'uaeio', 'uaeiou')

Example 5
Input: $str = 'aeioaeioa'
Output: ()

Analysis

In terms of lines of code a simple way to solve this challenge would be to use Algorithm::Combinatorics 'subsets' and check each subset to see if it met the 'vowel substring' criterion. But that would quickly get very slow if the substring was long - say over 20 characters.

So I found a better, if a bit more complicated way.

First, let's get rid of some hopeless cases, such as a string missing any of the 5 vowels. That will also eliminate any string with fewer than 5 characters.

Now let's break the string into substrings at the places where non-vowels occur, so for example 'aeiouxuoiea' splits into substrings 'aeiou' and 'uoiea'.

For each substring I then test all the sub-substrings of 5 or more letters to see if they contain at least one of each vowel. If they do, they are an answer to the challenge, because we've already eliminated any non-vowels.

I tried this on a string of 10 000 characters comprising random vowels randomly interspersed with 10% of 'x', and the answer came back in about a second.

Try it 

Your input:



eg: aeioxeiouxueuiao

Script


#!/usr/bin/perl

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

use v5.26;    # The Weekly Challenge - 2026-05-18
use utf8;     # Week 374 - task 1 - Count vowel
use warnings; # Peter Campbell Smith
binmode STDOUT, ':utf8';
use Encode;

count_vowel('aeiou');
count_vowel('aaeeeiioouu');
count_vowel('aeiouuaxaeiou');
count_vowel('uaeiou');
count_vowel('aeioaeioa');

sub count_vowel {
    
    my ($string, @result, @subs, $sub, $sub_length, $s, $f, $subsub);
    
    # initialise
    $string = lc($_[0]);
    say qq[\nInput:  '$string'];
    @result = ();
    
    # quick discards
    for ('a', 'e', 'i', 'o', 'u') {
        if ($string !~ m|$_|) {
            say qq[Output: ()];
            return;
        }
    }
    
    # segment string at non-vowels
    push @subs, $1 while $string =~ m|([aeiou]+)|g;
    SUB: for $sub (@subs) {
        
        # eliminate substring if too short or missing a vowel
        $sub_length = length($sub);
        next SUB if $sub_length < 5;
        
        # look for string of vowels
        for $s (0 .. $sub_length - 5) {
            SUBSUB: for $f (4 .. $sub_length - 1) {
                $subsub = substr($sub, $s, $f - $s + 1);
                for ('a', 'e', 'i', 'o', 'u') {
                    next SUBSUB if $subsub !~ m|$_|;
                }
                push @result, $subsub;
            }
        }
    }
    say qq[Output: ('] . join(q[', '], @result) . q[')];
}

20 lines of code

Output from script


Input:  'aeiou'
Output: ('aeiou')

Input:  'aaeeeiioouu'
Output: ('aaeeeiioou', 'aaeeeiioouu', 'aeeeiioou', 'aeeeiioouu')

Input:  'aeiouuaxaeiou'
Output: ('aeiou', 'aeiouu', 'aeiouua', 'eiouua', 'aeiou')

Input:  'uaeiou'
Output: ('uaeio', 'uaeiou', 'aeiou')

Input:  'aeioaeioa'
Output: ()

 

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