# Find my polyphthongs!

For the purposes of this challenge, a polyphthong is defined as a contiguous slice of a String, that only contains vowels, and has length at least 2. Given a non-empty String as input, your task is to output all the polyphthongs it contains.

For example, "abeoic" has the following contiguous slices (space-separated):

a b e o i c ab be eo oi ic abe beo eoi oic abeo beoi eoic abeoi beoic abeoic


Removing those that contain anything other than vowels, or have length smaller than 2, we get our desired polyphthongs:

eo oi eoi


Your submissions must abide by the following rules:

• You can choose either lowercase or uppercase for I/O, but the output case must match the input case.

• The vowels are aeiou (for lowercase) and AEIOU (for uppercase). y / Y is not considered a vowel.

• The input will only contain printable ASCII.

• If a polyphthong appears multiple times, you may choose to output it only once or output all its occurrences.

• Any reasonable I/O format and method is allowed (lists of characters are also fine, for both input and output).

## Test Cases

Input  ->  Output (lowercase)

r67^^()*6536782!87                -> []
programming puzzles and code golf -> []
aaand... i won!                   -> ['aa', 'aa', 'aaa']
abeoic                            -> ['eo', 'oi', 'eoi']
yah eioo ala                      -> ['ei', 'io', 'oo', 'eio', 'ioo', 'eioo']
@yabeeeayio__e                    -> ['ee', 'ee', 'ea', 'io', 'eee', 'eea', 'eeea']
0ioen0aaiosnjksd                  -> ['io', 'oe', 'aa', 'ai', 'io', 'ioe', 'aai', 'aio', 'aaio']


Note that for test cases 3 and 6, you may output 'aa' and 'ee' respectively only once (See the fourth rule).

This is , the shortest submission in bytes in every language wins!

• Note that this was originally posted as a CMC (Chat Mini Challenge) in The Nineteenth Byte, but Adám said that it is suitable for Main, so I ended up posting this. Nov 1, 2017 at 13:59
• I your third test case, 'aa' appears twice. Does one have to output the same string multiple times if it appears at various locations or can one only output unique polyphtongs? Nov 1, 2017 at 14:00
• @JonathanFrech Ok, I guess outputting the unique polyphtongs is fine. Will edit. Nov 1, 2017 at 14:01
• Does the order of output matter?
– ovs
Nov 1, 2017 at 14:03
• @Xophmeister For the purposes of this challenge, a polyphthong is defined as - I know that's not the correct linguistic definition :-) Nov 2, 2017 at 15:39

# Python 2, 102 97 bytes

thanks to @JonathanFrech for -5 bytes

w=input();l=range(len(w)+1)
print{w[a:b]for a in l for b in l if b-a>1<set(w[a:b])<=set('aeiou')}


Try it online!

lowercase I/O

• I think you do not need ...AEIOU', since you are allowed to only take lowercase letters as input. Nov 1, 2017 at 14:06
• Nov 2, 2017 at 0:22
• @JonathanFrech print([w[a:b]for a in l for b in l[a+2:]if{*w[a:b]}<={*'aeiou'}]) works for 93.
– Lynn
Nov 2, 2017 at 0:53
• @Lynn And your solution produces 96 Python 2 bytes. Nov 2, 2017 at 6:16

# JavaScript (ES6), 77 75 bytes

Expects input in lowercase. Outputs unique polyphthongs without repeating.

w=>(r=[],g=s=>w.match(s)&&[...'aeiou'].map(c=>g(s+c),s[1]&&r.push(s)))&&r


### Test cases

let f =

w=>(r=[],g=s=>w.match(s)&&[...'aeiou'].map(c=>g(s+c),s[1]&&r.push(s)))&&r

console.log(JSON.stringify(f("r67^^()*6536782!87")))
console.log(JSON.stringify(f("programming puzzles and code golf")))
console.log(JSON.stringify(f("aaand... i won!")))
console.log(JSON.stringify(f("abeoic")))
console.log(JSON.stringify(f("yah eioo ala")))
console.log(JSON.stringify(f("@yabeeeayio__e")))
console.log(JSON.stringify(f("0ioen0aaiosnjksd")))

### How?

We recursively build the tree of all possible polyphthongs, pruning branches as soon as the current node is not contained in the input anymore, and saving all matching nodes of at least 2 characters.

w => (                      // given the input w
r = [],                   // r = array of results
g = s =>                  // g = recursive function taking s
w.match(s) &&           // if w contains s:
[...'aeiou'].map(c =>   //   for each vowel c:
g(s + c),             //     do a recursive call with s + c
s[1] &&               //     if s is at least 2-character long:
r.push(s)             //       push it into r
)                       //   end of map()
)                         // initial call to g() with s = ''
&& r                        // return r


## Retina, 23 20 bytes

M!&[aeiou]+
r!&..+


Try it online!

This prints all occurrences of a polyphthong.

### Explanation

Retina does have a way to get all overlapping matches, but what this really means is that it will look for one match from each position. So if there are multiple matches from the same position, this will only return one of them. The only way to really get all overlapping matches is to use this feature twice, once matching left to right and once right to left (so that we first get the longest possible match from each possible starting position, and then we also get all matches for the possible ending positions).

So the actual program:

M!&[aeiou]+


Get all overlapping runs of vowels. What this really means is to get all suffixes of all vowel runs.

r!&..+


Now get all prefixes which are at least of length 2, by matching from right to left. The M is implicit here, because it's the final line of the program.

• Can you explain the code?
Nov 1, 2017 at 14:47
• !&[aeiou]{2,} is so close to correct, is there a way to get it greedier so it matches against io? Nov 1, 2017 at 14:59
• @AdmBorkBork My explanation sort of covers why that can't work. Retina doesn't fiddle with the actual regex engine, so the most & can do is to try for a match from each position, so you can't have multiple matches of different length from the same position. That's why I need a second stage. Nov 1, 2017 at 15:02
• Nice explanation, thanks. Nov 1, 2017 at 15:03

# QuadS, 20 + 1 = 21 bytes

⊃,/⍵
[aeiou]+
1↓,\⍵M


with the o flag

Try it online!

In order of things happening:

[aeiou]+ on each match of this PCRE

,\⍵M prefixes of the Match

1↓ drop the first one (which has one one vowel)

,/⍵ concatenate all the lists of prefixes

⊃ disclose (because reductions / enclose)

This is equivalent to the Dyalog APL tacit function:

{⊃,/⍵}'[aeiou]+'⎕S{1↓,\⍵.Match}⍠'OM'1


Try it online!

# Mathematica, 92 bytes

Select[Join@@Partition[r,i,1]~Table~{i,2,Length[r=(S=Characters)@#]},SubsetQ[S@"aeiou",#]&]&


# Java (OpenJDK 8), 138135 134 bytes

s->{String e,x="";for(int i=0,j,y=s.length();i<=y;i++)for(j=y;j>i;x+=e.matches("[aeiou]{2,}")?e+" ":"")e=s.substring(i,j--);return x;}


Try it online!

• Actually you can replace L’$ with Ḋ for 9 bytes. An equivalent would be ẆṫLḊḟÐḟØc. Nov 1, 2017 at 14:12 # C (gcc), 104 bytes (99 bytes with lowercase only or uppercase only) Yeah, it leaks - so what? #include<string.h> a;f(char*s){*s&&f(s+1);for(a=strspn(s=strdup(s),"AEIOUaeiou");a>1;)s[a--]=0,puts(s);}  Try it online! # R, 137 bytes outgolfed by Mark! function(S)(x=unlist(sapply((s=el(strsplit(S,"[^aeiou]")))[nchar(s)>1],function(x)substring(x,1:(n=nchar(x)),rep(n:1,e=n)))))[nchar(x)>1]  Try it online! function(S){ s <- el(strsplit(S,"[^aeiou]")) # split on non-vowels s <- s[nchar(s)>1] # vowel groups of length at least 2 p <- function(x){ # generates all substrings of inputs n <- nchar(x) start <- 1:n stop <- rep(n:1, n) # this will generate dups substring(x, start, stop) } q <- unlist(sapply(s, p)) # all substrings q <- q[nchar(q)>1] # all length-2 or more substrings }  • You do not need unique. Nov 1, 2017 at 14:30 • "Any reasonable I/O format and method is allowed (lists of characters are also fine, for both input and output)." I've not tried it out, but I suspect this could be quite a lot shorter if you use character lists from the start. Nov 1, 2017 at 15:33 • @user2390246 perhaps. I'm not convinced that it would help necessarily, but that's probably just because the approach to isolate runs of vowels would be quite different and I can't wrap my head around it right now. Nov 1, 2017 at 15:48 # Perl 5, 53 +1 (-p) /[aeiou]{2,}(?{$h{$&}++})(?!)/g;$_=join$",sort keys%h  Try It Online # PowerShell, 93 88 bytes param($a)0..($b=$a.count-1)|%{($i=$_)..$b|%{-join$a[$i..$_]}}|?{$_-match'^[aeiou]{2,}$'}


Try it online!

Uses lowercase or uppercase I/O (or a mix!).

Borrows code from my answer on Exploded Substrings to get all the substrings, then pulls out those that regex -match against ^[aeiou]{2,}$ -- i.e., those that are at least two vowels in length and only vowels. Those strings are left on the pipeline and output is implicit. # 05AB1E, 10 bytes Œʒg≠}ʒžMм_  Try it online! Explanations: Œʒg≠}ʒžMм_ Œ Push all substrings (abeoic => a, b, e, ..., eoi, eoc, ... abeioc) ʒ } Filter elements for which result is 1 g≠ Push 1 if length is != 1, 0 otherwise ʒ Filter elements for which result is 1 žMм Remove all occurences of 'aeiou' from element _ Negative bool: push 1 if length == 0, 0 otherwise  • Nice answer! I had ŒʒžMм_}ʒg≠ Nov 1, 2017 at 16:47 • @Mr.Xcoder Thanks. I also had ŒD1ùKʒžMм_ for 10 bytes. I'm trying to find a way to golf it down though Nov 1, 2017 at 16:50 • -1 byte by replacing ʒg≠} with ISK. Nov 18, 2021 at 10:32 # Haskell, 148137130123 118 bytes Thanks to @Laikoni for -11 bytes, further -7 bytes by pointing me to golfing tips, another -7 bytes, and yet another -5 bytes, for a total of whopping -30 bytes. This looked like a good fit for Haskell but the result doesn't seem to agree. I guess Haskell was an OK-ish choice after all. I'm still annoyed by the way subsequences works though. import Data.List v=(elem"aeiou") p s=nub$do x<-groupBy((.v).(&&).v)s;[y|y@(c:_:_)<-subsequences x,v c,yisInfixOfx]


Try it online!

• Welcome to Haskell golfing! You might be interested in our collection of golfing tips, the guide to golfing rules and Of Monads and Men, our Haskell chat room. Nov 1, 2017 at 18:08
• Some notes on your answer: Newlines have the same byte count as ;, but increase the readability of the code. You always use e together with v, so you can directly declare e=(elem"aeiou"). y!!0 is shorter than head y. There is concatMap instead of concat.map, but even shorter is (=<<) from the list monad wich has the same effect. Nov 1, 2017 at 18:11
• You can import Data.Lists instead of Data.List. The former has all functions of the latter, but also additional stuff like powerslice, which gives a list of all continuous subsequences.
– nimi
Nov 1, 2017 at 22:33
• In the list comprehension, you can match on y@(h:_:_) to drop length y>1 and shorten v(y!!0) to v h. Nov 2, 2017 at 0:03
• I have two more aces up my sleeve: (1) (\x y->v x&&v y) can be shortened by converting to point-free, either manually using this tip or by using pointfree.io. (2) The list monad can also be used with the do notation, that is do x<-l;[...] is the same as l>>=(\x->[...]). Btw, on TIO you can put your main into the header or footer field to have the byte count match the actual submission. Nov 2, 2017 at 9:20

# Perl, 45 bytes

local $,=" ";print$_=~/(?=([AEIOU]{2,}))/ig;

• Welcome to PPCG! Nice first post! Nov 5, 2017 at 21:35
• In case you're wondering about the downvote, that was automatically placed by the Community bot account because your post was edited. Sorry, nothing we can really do about it, it's dumb behaviour. Hopefully the upvotes should trigger automatic downvote retraction. Nov 5, 2017 at 21:38

# R, 120 bytes 110 bytes

function(x){k=nchar(x);i=k:1;e=expand.grid(i,i[-1]);grep("^[aeiou]+$",mapply(substr,x,e[,2],e[,2]+e[,1]),v=T)}  Try it online! How it works function(x){ #initalize the anonymous function where input is stored in x k=nchar(x) #set k to the number of characters in x i=k:1 #create vector of integers from k to 1 e=expand.grid(i,i[-1]) #create matrix of full outer join on i #except in the second column, limit i to being less than k grep("^[aeiou]+$",          #search for strings made of only vowels
mapply(substr,         #map the substring function
x,              #with x as the string to subset
e[,2],          #start at the second column of the outer join
e[,2]+e[,1]     #end at the sum of the sum of the first and second columns
),
v=T                    #if a match is found, return it's value
)
}                             #by default, R returns the last line of a function

• 105 bytes nice approach, I'll add a comment to my solution noting that you have outgolfed me :) Nov 21, 2017 at 20:56
• I'll be honest, I was very pleased that I was able to come up with an alternate solution to yours :) Normally you're already light years ahead of me or figuring out all the code I left on the table.
– Mark
Nov 21, 2017 at 22:01

# C, 119 bytes

f(char*s){*s&&f(s+1);char*t,*b=calloc(strlen(s),1);for(t=b;*s==65|*s==69|*s==73|*s==79|*s==85;b[1]&&puts(b))*t++=*s++;}


Try it online!

# JavaScript (ES6), 105 bytes

s=>eval('a=[];l=i=s.length;while(i--){j=l;while(j--)if(/^[aeiou]{2,}$/.test(t=s.slice(i,j)))a.push(t)}a')  Probably has a lot of golfing left to do. let f= s=>eval('a=[];l=i=s.length;while(i--){j=l;while(j--)if(/^[aeiou]{2,}$/.test(t=s.slice(i,j)))a.push(t)}a')
console.log(JSON.stringify(f('r67^^()*6536782!87')))
console.log(JSON.stringify(f('programming puzzles and code golf')))
console.log(JSON.stringify(f('aaand... i won!')))
console.log(JSON.stringify(f('abeoic')))
console.log(JSON.stringify(f('yah eioo ala')))
console.log(JSON.stringify(f('@yabeeeayio__e')))
console.log(JSON.stringify(f('0ioen0aaiosnjksd')))

# Perl 5, 44 + 1 (-n) = 45 bytes

map{say}/(?=([aeiou]{$.}))/g while$.++<y///c


Try it online!

# C, 105 75 bytes

A function accepting a pointer to lowercase input, and producing space-separated strings on standard output:

i;f(char*p){for(i=strspn(p,"aeiou");i>1;)printf("%.*s ",i--,p);*p&&f(p+1);}


### Test program

#include <stdio.h>

int main(int argc, char **argv)
{
for (int i = 1;  i < argc;  ++i) {
char *in = argv[i];
printf("'%s' -> [ ", in);
f(in);
puts("]");
}
}


### Demo

'r67^^()*6536782!87' -> [ ]
'programming puzzles and code golf' -> [ ]
'aaand... i won!' -> [ aaa aa aa ]
'abeoic' -> [ eoi eo oi ]
'yah eioo ala' -> [ eioo eio ei ioo io oo ]
'@yabeeeayio__e' -> [ eeea eee ee eea ee ea io ]
'0ioen0aaiosnjksd' -> [ ioe io oe aaio aai aa aio ai io ]


### Explanation

#include <string.h>
#include <stdio.h>

void find_polyphthongs(char *p)
{
/* from longest polyphthong substring down to 2 */
for (int i = strspn(p,"aeiou");  i >= 2;  --i) {
/* print exactly [p .. p+i] */
printf("%.*s ", i, p);
}

/* tail-recurse to next char */
if (*p) {
find_polyphthongs(p+1);
}
}


Using GCC on Debian Linux, I seem to get away with the incompatible implicit declarations of strchr() and printf(). Other platforms may require <stdio.h> and <string.h> to be included.

Try it online (requires Javascript).

• Can f(p)char*p; not be f(char*p)? Nov 1, 2017 at 18:00
• Quite right - I originally had output to caller-allocated storage: f(s,d)char*s,*d. Nov 1, 2017 at 18:01
• Nov 1, 2017 at 18:01

# APL (Dyalog), 53 bytes

This is a Dfn (direct function). Usage is p '<argument>'. Fair warning: this is not very efficient and times out for input > 8 characters on TIO, but works normally when given enough time.

p←{(G∊⊃,/⌽,\∘⌽¨,\⌽⍵)/G←⊃,/{(,v∘.,⊢)⍣⍵⊢v←'aeiou'}¨⍳≢1↓⍵}


Try it online!

Thanks to @Adám for 16 bytes!

### How it works:

This is easier to understand if we break the code in smaller portions:

• Part 1 - G←⊃,/{(,v∘.,⊢)⍣⍵⊢v←'aeiou'}¨⍳≢1↓⍵: This part of the function takes the length of the (right) argument and mixes the vector aeiou to itself that many times, yielding every possible combination of [2, length(right arg)] vowels.
• Part 2 - (G∊⊃,/⌽,\∘⌽¨,\⌽⍵)/: This part checks which element(s) of G are members of the substrings of the input. This returns a boolean vector, with 1's at the indices of the vowel combinations that are present in the input and 0's where they're not. The resulting vector is then mapped (/) over G, returning the elements corresponding to the truthy values.

The whole thing is then assigned to p. p← is not included in the byte count because it's not necessary, it just makes using the function easier.

• Golfed further. Also, you shouldn't use ⊆ to filter. Use /.
Nov 9, 2017 at 12:45

f[]=[]
f(h:t)=filter(all(elem"aeiou"))[h:take i t|i<-[1..length t]]++f t


Try it online!

(2..(b=(a=gets).size-1)).to_a.flat_map{|i|(0..(b-i)).to_a.map{|j|a[j,i]}}.select{|k|k=~/^[aeiou]+$/}  This is my first attempt at golfing, and I'm sure there are lots of ways to shorten this code. # Ruby, 80 bytes ->s{[*0..z=s.size-2].product([*2..z]).map{|v|s[*v][/[aeiou]{2,}/]}.uniq.compact}  Try it online! • .compact can be -[nil] Nov 21, 2017 at 22:41 # Pyth, 15 bytes f&tT!-T"aeoi".:  Try it online! Definitely golfable, I want to get it better before writing out explanation. # T-SQL (SQL Server 2014), 281 bytes ;with s as(select substring(@,1,1)C,stuff(@,1,1,'')D,1 R union all select substring(D,1,1),stuff(D,1,1,''),R+1from s where len(D)>0),c as(select R i,C w from s where C LIKE'[aeiou]'union all select R,w+C from c join s ON i+1=R where s.C LIKE'[aeiou]')select w from c where len(w)>1  Input give by declare @ varchar(max) = 'abeoic'  Uses a common table expression s to blow the input apart into ordered individual letters, and then a second common table expression c to generate all ordered combinations, throwing out non vowels. SQL Fiddle # PHP, 139 bytes function y($s){$p=[];$l=strlen($s);for($i=2;$i<=$l;$i++)for($j=0;$j<=$l-$i;$j++)strspn($a=substr($s,$j,$i),'aeiou')==$i&&$p[]=$a;return$p;}


Online demo

function yreadable($s) {$p = [];
$l = strlen($s);
for($i=2;$i<=$l;$i++)
for($j=0;$j<=$l-$i; $j++) strspn($a=substr($s,$j,$i),'aeiou')==$i
&& $p[] =$a;
return \$p;
}


## How it works

Select sub-strings (beginning with the length of 2) consisting of adjacent characters and move along string. Collect any sub-strings that only contain vowels. Repeat with longer sub-strings.

For string 'abcdef' these are the substrings generated and checked:

'ab','bc','cd','de','ef'
'abc','bcd','cde','def'
'abcd','bcde','cdef'
'abcde','bcdef',
'abcdef'


# Vyxal 2.6.0pre1 , 6 bytes

K~Ḣ'AA


K      # Substrings
~Ḣ    # Filtered by a[:1] exists (len(a) > 1)
'   # Filtered by...
A # All...
A  # Are vowels.


# Vyxal, 9 bytes

K'Ḣ;'kv↔=


Try it Online!

K         # Substrings
' ;      # Filtered by...
Ḣ       # a[1:] is nonempty
'     # Filter again by...
↔  # Removing everything but...
kv   # Vowels
= # Leaves it identical to the original.
`