# Rememebere tehe vowelese!

## Input

A string of printable ASCII characters, for example:

This is an example string.


## Output

For every consonant (BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz) that is not followed by a vowel (AEIOUaeiou) add the last vowel before it, in lowercase.
Consonants before the first vowel are left as-is:

Thisi isi ana examapale seterinigi.


## Test cases

AN EXAMPLE WITH A LOT UPPERCASE (plus some lowercase)
=> ANa EXAMaPaLE WITiHi A LOTo UPuPEReCASE (pelusu some lowerecase)

And here comes a **TEST** case with 10% symbols/numbers(#)!
=> Anada here comese a **TESeTe** case witihi 10% siyimiboloso/numuberese(#)!

This is an example string.
=> Thisi isi ana examapale seterinigi.

abcdefghijklmnopqrstuvwxyz

A pnm bnn
=> A panama banana

Tell me if you need more test cases!
=> Telele me ifi you neede more tesete casese!


## Scoring

As this is , the answer with the lowest byte-count in each language wins (no answer will be accepted).

• So, should the inserted vowels be always lowercase, while the text might be both uppercase and lowercase? – Erik the Outgolfer Jun 6 '18 at 17:53
• Can the output be in the form of a list/array? – Nathan Dimmer Jun 6 '18 at 17:54
• @EriktheOutgolfer Yes, I did not want uppercase where we need lowercase, but it would have overcomplicated the challenge if one had to check the case of adjacent letters – wastl Jun 6 '18 at 17:55
• Eat healthy kids, try A pnm bnn! – Stewie Griffin Jun 6 '18 at 20:09
• Does anyone else think "How Italians" needs to go in the title somewhere? – Artelius Jun 7 '18 at 1:17

# Retina, 48 bytes

i(?<=([aeiou]).*?[^\W\d_aeiou])(?![aeiou])
$l$1


Try it online! Explanation: The lookahead searches for a point not followed by a vowel, while the lookbehind searches for an immediately preceding consonant and a previous vowel, which is then inserted in lower case.

# JavaScript (ES6), 108 105 bytes

(Saved 3 bytes thanks to @Shaggy.)

f=s=>(t=(s+=' ').replace(/[aeiou]|[a-z][^aeiou]/ig,r=>r[1]?r[0]+v.toLowerCase()+r[1]:v=r,v=''))!=s?f(t):s


Searches for vowels or for consonants with no following vowel:

/[aeiou]|[a-z][^aeiou]/ig


(We don't need to search for consonants explicitly, because vowels are excluded based on the /[aeiou]|....)

Vowels are stored in v, and consonants with no following vowel have v inserted:

r[1]?r[0]+v.toLowerCase()+r[1]:v=r


(If r[1] exists, we've matched on a consonant plus non-vowel.)

If nothing has been changed, we return the input. Otherwise, we recurse on the replaced string.

f=s=>(t=(s+=' ').replace(/[aeiou]|[a-z][^aeiou]/ig,r=>r[1]?r[0]+v.toLowerCase()+r[1]:v=r,v=''))!=s?f(t):s

console.log(f('A pnm bnn'));
console.log(f('abc'));
console.log(f('AN EXAMPLE WITH A LOT UPPERCASE (plus some lowercase)'));
console.log(f('And here comes a **TEST** case with 10% symbols/numbers(#)!'));
console.log(f('This is an example string.'));
console.log(f('abcdefghijklmnopqrstuvwxyz'));
console.log(f('Tell me if you need more test cases!'));

• This is even better. I really need to look at regex – Luis felipe De jesus Munoz Jun 6 '18 at 19:45
• +1 smart idea to use replace over map + join – Downgoat Jun 6 '18 at 19:56
• Based of yours an (almost) working version without recursion: s=>s.replace(/[aeiou][^a-z]*([a-z](?![aeiou]))+/gi,s=>s.replace(/(?!^)./g,a=>a+s[0].toLowerCase())) I can't seems to have issues with sequences of non-letters though – Downgoat Jun 6 '18 at 20:06
• Recursion certainly simplifies things here. – Rick Hitchcock Jun 6 '18 at 20:14
• (s+=' ') should save a few bytes. – Shaggy Jun 6 '18 at 22:01

# Python 2, 134 119 bytes

def f(s,v=''):u=s[:1];return s and u+v*(u.isalpha()-g(u)-g((s+u)[1]))+f(s[1:],[v,u.lower()][g(u)])
g='aeiouAEIOU'.count


Try it online!

EDIT: 15 bytes thx to Lynn

• I fiddled with it a little for 119 bytes. – Lynn Jun 7 '18 at 4:59
• @Lynn: Love the <vowels>.count. – Chas Brown Jun 7 '18 at 5:32

# Standard ML, 225 223 bytes

str o Char.toLower;fun?c=String.isSubstring(it c)"aeiou"fun g(x,l)$d=(fn l=>if Char.isAlpha$andalso not(?d)then if? $then(it$,l)else(x,l^x)else(x,l))(l^str$)fun f$(c::d::r)=f(g$c d)(d::r)|f$[c]= #2(g$c c);f("","")o explode;  Try it online! Less golfed: val lower = str o Char.toLower fun isVowel c = String.isSubstring (lower c) "aeiou" (* c is the current char, d is the next char, x is the last vowel and l the accumulator for the resulting string *) fun g (x,l) c d = if Char.isAlpha c andalso not (isVowel d) then if isVowel c then (lower c, l^str c) else (x, l^str c^x) else (x, l^str c) fun f t (c::d::r) = f (g t c d) (d::r) | f t [c] = #2(g t c #"d") val h = f ("","") o explode;  Try it online! • wow, ML golf looks really interesting! I love it and the use of the $ variable name. – Lynn Jun 7 '18 at 5:50
• @Lynn I wrote a tip about identifier renaming some time ago and planned to write one about it as well, but haven't gotten around doing so yet. – Laikoni Jun 7 '18 at 13:50

# sed 4.2.2, 64 bytes

:
s/(([aeiou])[^a-z]*[b-df-hj-np-tv-z])([^aeiou]|$)/\1\l\2\3/I t  Try it online! • I'll be honest, my goal here is just to try to beat perl by a couple of bytes. Let's see if it holds :) – KernelPanic Jun 7 '18 at 8:36 # Perl 5, 6867 59 bytes perl -pe '$v="[aeiou])";1while s/($v[^a-z]*[b-z]\K(?<!$v(?!$v/\L$1/i'


Here's a great example of the usefulness of \K, and I can't believe I didn't know about this feature before Dom Hastings pointed it out.

I haven't been able to get the right behavior with just using s///g, so an actual loop seems necessary. (It's possible that the right use of a look-behind assertion could work without an explicit while -- but I haven't found it.)

• Nice approach! Wasn't able to come up with anything better, but managed to get 6 bytes off: Try it online! – Dom Hastings Jun 7 '18 at 10:08
• @DomHastings: Even shorter (down to 58 bytes) by factoring out [aeiou]) to variable: Try it online! – ShadowRanger Jun 7 '18 at 19:26

# JavaScript ES6, 115 bytes

Saves 8 bytes thanks to @ETHProductions

s=>[x="",...s].map((i,j)=>(r=/[aeiou]/i).test(i)?x=i:/[a-z]/i.test(i)&&!r.test(s[j]||1)?i+x.toLowerCase():i).join


I have managed to inflate this more in the process of golfing it O_o but it also fixes a bug

s=>[x="",...s].map(             // Create a new array with x storing last vowel
// This also offsets indexes by one so rel to original str refers to next char
(i,j)=>                      // Going through each char...
(r=/[aeiou]/i).test(i)?   // If it's vowel, store it in x
x=i:
/[a-z]/i.test(i)          // If a letter (thats not a vowel excluded by above)
&&!r.test(s[j]||1)?    // Test if next char is *not* vowel
i+x.toLowerCase():i    // If it isn't, then add the most recent vowel after
).join                    // Combine back to string

• @RickHitchcock oh shoot totally forgot about ending char, fixing asap – Downgoat Jun 6 '18 at 19:42
• @RickHitchcock ok fixed – Downgoat Jun 6 '18 at 19:55
• Ah, yes thanks for the golf @ETHproductions – Downgoat Jun 6 '18 at 20:12

# JavaScript, 88 82 Bytes

Done with a single regular expression:

Original Version (88 Bytes):

s=>s.replace(/(?<=([aeiou]).*?(?![aeiou])[a-z])(?=[^aeiou]|$)/gi,(_,c)=>c.toLowerCase())  Updated Version (82 Bytes) after looking at Neil's regular expression: s=>s.replace(/(?<=([aeiou]).*?[^\W\d_aeiou])(?![aeiou])/gi,(_,c)=>c.toLowerCase())  var tests = { "AN EXAMPLE WITH A LOT UPPERCASE (plus some lowercase)": "ANa EXAMaPaLE WITiHi A LOTo UPuPEReCASE (pelusu some lowerecase)", "And here comes a **TEST** case with 10% symbols/numbers(#)!": "Anada here comese a **TESeTe** case witihi 10% siyimiboloso/numuberese(#)!", "This is an example string.": "Thisi isi ana examapale seterinigi.", "abcdefghijklmnopqrstuvwxyz": "abacadefegehijikiliminopoqorosotuvuwuxuyuzu", "A pnm bnn": "A panama banana", "Tell me if you need more test cases!": "Telele me ifi you neede more tesete casese!" }; for ( test in tests ) { var result = (s=>s.replace(/(?<=([aeiou]).*?[^\W\d_aeiou])(?![aeiou])/gi,(_,c)=>c.toLowerCase()))(test); console.log( result === tests[test], result ); } # Japt-P, 28 bytes ó@\ctX ©\VtYÃËè\v ?P=D:D¬qPv  Try it online! ### Unpacked & How it works UóXY{\ctX &&\VtY} mD{Dè\v ?P=D:Dq qPv UóXY{ } Split the string between any two chars that don't satisfy... \ctX &&\VtY The first char is a consonant and the second is a non-vowel mD{ And map... Dè\v If this item is a vowel... ?P=D Assign it to P and return as-is :Dq qPv Otherwise, split the item into chars and join with P lowercased (P starts with "", so beginning consonants are not affected) -P Join with ""  The ó function wins over any kind of regexes. • Nice one, ya beat me :D. – Magic Octopus Urn Jun 12 '18 at 18:00 • Nicely done - I gave myself severe brainache with this one! – Shaggy Jun 13 '18 at 15:05 # JavaScript (Node.js), 146143132127 125 bytes (a,v="")=>[...a].map((b,i)=>(w=/[aeiou]/i).test(b)&&(v=b)?b:w.test(a[i+1]||b)||!b.match(/[a-z]/i)?b:b+v.toLowerCase()).join  Try it online! # Perl 6, 75 73 71 69 bytes {({S:i/.*(<[aeiou]>).*<-[\W\d_aeiou]><()><![aeiou]>/$0.lc()/}...*eq*).tail}


Try it

{({S:i{.*(<[aeiou]>).*<-[\W\d_aeiou]><()><![aeiou]>}=$0.lc}...*eq*).tail}  Try it {({S:i{.*(<[aeiou]>).*<:L-[_aeiou]><()><![aeiou]>}=$0.lc}...*eq*).tail}


Try it

{({S:i{.*(<[aeiou]>).*<:L-[_aeiou]><(<![aeiou]>}=$0.lc}...*eq*).tail}  Try it ## Expanded: { # bare block lambda with implicit parameter$_

(
# generate a sequence

{  # code block used to generate the values

S               # substitute (not in-place)
:i              # :ignorecase
{

.*              # start at end of string

( <[aeiou]> )   # store the previous vowel in $0 .* <:L - [_aeiou]> # letter other than a vowel <( # ignore everything before this # this is where $0.lc gets inserted

# )>            # ignore everything after this

<![aeiou]>      # not a vowel (zero width lookahead)

} = $0.lc # replace with lowercase of the earlier vowel } ... # keep generating until: * eq * # there are two equal strings (no changes) ).tail # get the last value }  # Python 3, 125 bytes lambda s,v='[^aeiouAEIOU':sub(f'(?<={v}\W\d])(?={v}]|$)',lambda m:sub(f'{v}]','',s[:m.end()])[-1:].lower(),s)
from re import*


Try it online!

Python 3.6 allows us to (ab)use f-strings to reuse our set of vowels (and for four more characters saved, the beginning of an inverted regex character class) cheaply (a f prefix on each string, then {v} as needed, instead of the '+v+' you'd need with concatenation, or the [^aeiouAEIOU you'd insert literally.

The regex that matches no characters, just a position, avoids issues with the non-overlapping matches normal regexes require, and removes the need to backreference any part of the match; all we use the match object for is to get the slice index we use to find the prior vowel.

Partially de-golfed, it would be something like:

import re

def get_last_vowel(string):
'''
Returns the lowercase version of the last vowel in a string if
the string contains any vowels, otherwise, return the empty string
'''
try:
*restvowels, lastvowel = re.sub(r'[^aeiouAEIOU]', '', string)
except ValueError:
lastvowel = ''  # No vowels in string
return lastvowel.lower()

def rememebere_tehe_vowelese(string):
'''Inserts the lowercased last vowel seen after any consonant not followed by a vowel'''
return re.sub(r'(?<=[^aeiouAEIOU\W\d])(?=[^aeiouAEIOU]|$)', lambda match: get_last_vowel(string[:match.end()]), string)  # TSQL, 500 bytes  CREATE TABLE i (i CHAR(999)); INSERT i VALUES ('The rain in Spain stays mainly in the plain') DECLARE @w CHAR(999)=(SELECT i FROM i),@r VARCHAR(999)='';WITH d(n,c,i,q)AS(SELECT n,SUBSTRING(@w,n,1),CHARINDEX(SUBSTRING(@w,n,1),'AEIOUaeiou'),CHARINDEX(SUBSTRING(@w,n,1),'BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz')FROM(SELECT DISTINCT number n FROM master..[spt_values]WHERE number BETWEEN 1 AND LEN(@w))D)SELECT @r=@r+f.c+LOWER(COALESCE(CASE WHEN f.q<>0 AND COALESCE(d2.i,0)=0 THEN SUBSTRING(@w,(SELECT MAX(n)FROM d WHERE i<>0 AND n<f.n),1)END,''))FROM d f LEFT JOIN d d2 ON f.n=d2.n-1 SELECT @r  Table i is used for input • Assuming input to be present in a certain variable is generally not allowed. Can this be adapted to be a function instead? – Laikoni Jun 7 '18 at 18:56 • @Laikoni solution updated to match given rules – Jan Drozen Jun 8 '18 at 7:47 # SWI-Prolog, 593 bytes a(S,D):-atom_chars(S,D). g(_,[],_,-1). g(E,[E|_],R,R). g(E,[_|T],I,R):-N is I+1,g(E,T,N,R). c(A,E):-g(E,A,0,R),R > -1. v(X):-a('AEIOUaeiou',X). c(X):-a('BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz',X). d([_],_,R,R). d([H|T],_,I,R):-v(V),c(V,H),!,d(T,H,I,[H|R]). d([H,N|T],V,I,R):-c(C),c(C,H),v(W),c(W,N),!,d([N|T],V,I,[H|R]). d([H,N|T],V,I,R):-c(C),c(C,H),v(W),\+c(W,N),string_lower(V,LV),!,d([N|T],V,I,[LV,H|R]). d([H|T],V,I,R):-!,d(T,V,I,[H|R]). r([],Z,Z). r([H|T],Z,A):-r(T,Z,[H|A]). r(S,D):-r(S,D,[]). m(X,R):-a(X,O),r(O,P),r([''|P],Q),d(Q,'',I,[]),r(I,J,[]),atomic_list_concat(J,R).  Used only built-in predicates (without regex or list manipulating library). Usage: ?- m('A pnm bnn'). 'A panama banana' true .  # Haskell, 142 130 bytes ""& import Data.Char v=(elem"aeiouAEIOU") s&(x:y:z)|v y=x:s&(y:z) s&(x:y)|v x=x:[toLower x]&y|isAlpha x=x:s++s&y|1>0=x:s&y _&x=x  Try it online! The initial ""& is a partial application of the (&) function defined later on, and is placed so oddly to make TIO count the bytes in ""&, but not count the bytes that, in a full program, would be needed to assign that to any named value. Less golfed: import Data.Char (isAlpha, toLower) vowel :: Char -> Bool vowel = (elem"aeiouAEIOU") replace :: String -> String replace = go "" -- start by carrying no extra vowel where go _ "" = "" -- special case for "anything followed by vowel" so later cases can ignore next character go s (x:y:more) | vowel y = x : go s (y:more) go s (x:xs) | vowel x = x : go [toLower x] xs -- update the vowel we're carrying | isAlpha x = x : s ++ go s xs -- non-vowel letter not followed by a vowel | otherwise = x : go s xs -- some non-letter junk, just include it and carry on  There really ought to be a way to do this more concisely with a fold instead of recursion, but I couldn't figure it out. • Here is a very hacky way of defining a header such that f does not appear in the body: Try it online! – Laikoni Jun 8 '18 at 4:50 • There are two unnecessary spaces in v = ( and you can define g as an infix operator. – Laikoni Jun 8 '18 at 4:54 • Putting the base case g _""="" in last position saves a byte: g _ x=x (two bytes if you switch to infix as Laikoni suggests). – nimi Jun 8 '18 at 20:01 • Per our conventions you'd need to add parenthesis around ""& to make it an function. – Laikoni Jun 9 '18 at 20:24 # 05AB1E, 34 bytes vyžMylåil©1V}žPylåžM¹N>èå_Y&&i®«}J  Try it online! I take that back I can only shave 3 bytes off this monstrosity... I think I could shave the boolean down, but there MUST be 3 cases. 1 for vowels. 1 for consonants. 1 for the case that a digit/symbol exists. v # For each... y # Push current element. žM # Push lower-case vowels (aeiou). ylå # Lower-case current element is vowel? i©1V} # If so, put it in register, set Y to 1. žP # Push lower-case consonants (b...z) ylå # Is current char a consonant? žM¹N>èå_ # Push vowels again, is input[N+1] NOT a vowel? Y # Did we ever set Y as 1? && # All 3 previous conditions true? i®«} # Concat the current vowel to the current char. J # Join the whole stack. # '}' isn't needed here, b/c it's implied. # Implicit return.  # Powershell, 104 bytes based on Neil's regular expression. [regex]::Replace($args,'(?i)(?<=([aeiou]).*?[^\W\d_aeiou])(?![aeiou])',{"$($args.Groups[1])".ToLower()})


save it as get-rememebere.ps1. Script for testing:

$test = @" AN EXAMPLE WITH A LOT UPPERCASE (plus some lowercase) And here comes a **TEST** case with 10% symbols/numbers(#)! This is an example string. abcdefghijklmnopqrstuvwxyz A pnm bnn Tell me if you need more test cases! "@$expected = @"
ANa EXAMaPaLE WITiHi A LOTo UPuPEReCASE (pelusu some lowerecase)
Anada here comese a **TESeTe** case witihi 10% siyimiboloso/numuberese(#)!
Thisi isi ana examapale seterinigi.
A panama banana
Telele me ifi you neede more tesete casese!
"@

$result = .\get-rememebere.ps1$test
$result -eq$expected
$result  # Red, 276 bytes func[s][v: charset t:"AEIOUaeiou"c: charset u:"BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz"b: parse s[collect[any keep[thru c opt v]keep thru end]]p:""foreach c b[either find t e: last c: to-string c[p: e][parse c[any[copy p v | skip]]if find u e[append c lowercase p]]prin c]]  Try it online! Readable: f: func [ s ] [ v: charset t: "AEIOUaeiou" c: charset u: "BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz" b: parse s [ collect [ any keep [ thru c opt v ] keep thru end ] ] p: "" foreach c b [ e: last c: to-string c either find t e [ p: e ][ parse c [ any [ copy p v | skip ] ] if find u e [ append c lowercase p ] ] prin c ] ]  # Yabasic, 180 bytes A full program which takes input from STDIN and outputs to STDOUT Line Input""s$
x$="AEIOUaeiou" For i=1To Len(s$)
c$=Mid$(s$,i,1) ?c$;
If InStr(x$,c$)Then
v$=c$
Else
a=Asc(Upper$(c$))
If a>64And a<91And!InStr(x$,Mid$(s$,i+1,1))Then?v$;Fi
Fi
Next
`

Try it online!