Write a function that takes a string of letters and spaces (no need to handle non-letters) and performs the ANNOUNCER VOICE translation algorithm as follows:

  • First, uppercase everything.
  • For each word,
    • Elongate each consonant cluster by tripling each letter; except, if the word begins with a consonant cluster, do not elongate that cluster. For example, other should become OTTTHHHEEERRR but mother should become MOTTTHHHEEERRR.
    • Elongate the final vowel by tripling it.
  • In both cases of elongation, if you're tripling a letter, first coalesce it with duplicate letters on either side. For example, hill should become HIIILLL and bookkeeper should become BOOKKKEEPPPEEERRR.
  • For the purposes of this challenge, y counts as a consonant.
  • Clarification/simplification: You may assume that each pair of words is separated by a single space, and that the input contains no consecutive spaces, and that the input will not be the empty string.
  • Shortest code wins!

Test vectors:

> sunday sunday
> mia hamm
> chester alan arthur
> attention please
> supercalifragilisticexpialidocious
> moo
> Aachen
> Oooh
> grifffest
> k
> aaaabbbbc

Here's a reference implementation which I would move to an answer except that as of this morning the question's been closed. :P

import itertools,re
def j(s):return re.match('^[AEIOU]+$',s)
def c(s):return ''.join(sum(([h,h,h]for h in[k for k,g in itertools.groupby(s)]),[]))
def v(s):
 while len(s)>=2 and s[-2]==s[-1]:s=s[:-1]
 return s+s[-1]+s[-1]
def a(n):
 for w in n.split():
  if r:r+=' '
  ss=re.split('([AEIOU]+)', w.upper())
  for i,s in enumerate(ss):
   r += [v(s),s][any(j(t) for t in ss[i+1:])]if j(s)else[s,c(s)][i>0]
 return r
while 1:print a(raw_input('> '))
  • 2
    \$\begingroup\$ A request for the future: please avoid words and phrases like consonant cluster, coalesce, and elongation. A non-native English speaker like myself might need a dictionary to understand your post. \$\endgroup\$ – Dennis Jul 21 '17 at 15:51
  • \$\begingroup\$ It should be the vowels that are "elongated" :( \$\endgroup\$ – JOATMON Jul 21 '17 at 19:56
  • \$\begingroup\$ What is consonant cluster? \$\endgroup\$ – MilkyWay90 Nov 11 '18 at 20:41

APL (Dyalog), 175 bytes

1↓' +'⎕R' '⊢'[AEIOU][^AEIOU]+ '⎕R{m/⍨1,3×2≠/m←⍵.Match}'([AEIOU])\1*([^AEIOU]*? )' ' [AEIOU]' ' [^ AEIOU]+' '([^AEIOU ])\1*'⎕R'\1\1\1\2' '&' '&' '\1\1\1'⊢'$| |^'⎕R'  '⊢1(819⌶)⍞

Try it online!

 prompt for character input

1(819⌶) convert to uppercase (819 ≈ Big)

 pass the result further (serves to separate the strings and the 1)

'$| |^'⎕R' 'Replace:
 the end, any space, and the beginning
 → two spaces

 pass the result further (serves to separate two groups of strings)

'([AEIOU])\1*([^AEIOU]*? )' ' [AEIOU]' ' [^ AEIOU]+' '([^AEIOU ])\1*'⎕R'\1\1\1\2' '&' '&' '\1\1\1'Replace:
 any number of identical vowels and any number of non-vowels and a space
 → the vowel thrice and the unmodified consonants
 a space and a vowel
 → themselves
 a space and a consonant cluster
 → themselves
 a run of identical consonants
 → three of those vowels

'[AEIOU][^AEIOU]+ '⎕R{}Replace:
 a run of non-vowels and a space
 → the result of the following anonymous function with the namespace as argument:
  ⍵.Match the text that was found
  m← assign that to m
  2≠/ pair-wise different-from
   multiply by three
  1, prepend one
  m/⍨ use that to replicate m

 pass the result further (serves to separate two strings)

' +'⎕R' 'Replace:
 one or more spaces
 → with a single space

1↓ drop the initial letter (a space)

  • \$\begingroup\$ Does this work? 1↓' +'⎕R' '⊢'[AEIOU][^AEIOU]+ '⎕R{m/⍨1,3×2≠/m←⍵.Match}'([AEIOU])\1*([^AEIOU]*? )' ' [AEIOU]' ' [^ AEIOU]+' '([^AEIOU ])\1*'⎕R(s,'\2')'&' '&'(s←6⍴'\1')⊢'$| |^'⎕R' '⊢1(819⌶)⍞ \$\endgroup\$ – Adalynn Jul 20 '17 at 20:34
  • \$\begingroup\$ ^ Saves two bytes if it works ^ \$\endgroup\$ – Adalynn Jul 20 '17 at 20:35

JS (ES6), 138 134 129 bytes

s=>s.toUpperCase()[r="replace"](/(\w)\1/g,"$1")[r](/[AEIOU](?=[^AEIOU]*( |$))/g,s=>s+s+s)[r](/\B./g,s=>/[AEIOU]/.test(s)?s:s+s+s)

WAAAYYY TOOO MAAANNNYYY BYYYTTTEEESSS. Contains AEIOU 3 times, but I can't golf those into one.

-4 bytes thanks to HyperNeutrino


function v(str){
    return str.toUpperCase().replace(/(\w)\1/g,"$1").replace(/[AEIOU](?=[^AEIOU]*( |$))/g,s=>s+s+s).replace(/\B./g,s=>[..."AEIOU"].includes(s)?s:s+s+s);

I like to write, not read code.

  • 1
    \$\begingroup\$ "WAAAYYY TOOO MAAANNNYYY BYYYTTTEEESSSS" ... is in first place, ahead of APL. \$\endgroup\$ – Adalynn Jul 20 '17 at 20:49
  • \$\begingroup\$ I don't know JS, but can you replace s=>/[AEIOU]/.test(s) with /[AEIOU]/.test? \$\endgroup\$ – musicman523 Jul 20 '17 at 21:44
  • \$\begingroup\$ @musicman523 sadly, no, because it is the conditional in a ternary operator statement. \$\endgroup\$ – ABot Jul 20 '17 at 22:27
  • \$\begingroup\$ FYI, your handling of consonant clusters appears to be slightly incorrect; the proper output would be WAAAYYY TOOO MAAANNNYYY BYTEEESSS (i.e. don't elongate the initial cluster BYT). \$\endgroup\$ – Quuxplusone Jul 20 '17 at 22:47
  • \$\begingroup\$ Well, was in first place. \$\endgroup\$ – Adalynn Jul 21 '17 at 23:34

APL, 90 bytes

{1↓∊{s←{⍵⊂⍨1,2≠/⍵}⋄x↑⍨¨(3⌈≢¨s⍵)⌊≢¨x←s⍵/⍨(1+2×{⌽<\⌽⍵}∨~∧∨\)⍵∊'AEIOU'}¨w⊂⍨w=⊃w←' ',1(819⌶)⍵}


  • 1(819⌶)⍵: convert to uppercase
  • w⊂⍨w=⊃w←' ',: split on spaces
  • {...: for each word...
    • s←{⍵⊂⍨1,2≠/⍵}: s is a function that splits a string into groups of contiguous matching characters
    • ⍵∊'AEIOU': mark the vowels
    • (...): see which characters to triplicate
      • ~∧∨\: all consonants past the first vowel,
      • {⌽<\⌽⍵}: the last vowel.
      • : multiply the bit vector by two,
      • 1+: and add one. Now all selected characters have 3 and the rest have 1.
    • ⍵/⍨: replicate each character in by the given amount
    • x←s: split it up into strings of matching characters, and store this in x.
    • (3⌈≢¨s⍵): the length of each group of matching characters in the input word, with a maximum of 3.
    • ⌊≢¨: the minimum of that and the lengths of the groups in x.
    • x↑⍨¨: make each group be that length
  • 1↓∊: flatten the result and drop the first character (the space that was added at the beginning to help with splitting)
  • \$\begingroup\$ You beat Adám ... wow. \$\endgroup\$ – Adalynn Jul 21 '17 at 23:32
  • \$\begingroup\$ very neat! If you shuffle it around a bit and write it as a program (using prompt as suggested by Adám) you can shave off another 15 bytes: 1↓∊{c/⍨(≢¨g)⌈3×((⌽<\∘⌽)∨~∧∨\)'AEIOU'∊⍨c←⊃¨g←⍵⊂⍨1,2≠/⍵}¨w⊂⍨w=⊃w←' ',1(819⌶)⍞ \$\endgroup\$ – Gil Aug 24 '17 at 22:26

Python, 417 bytes

Here's a reference implementation in Python. Not terribly golfed.

import itertools,re
def j(s):return re.match('^[AEIOU]+$',s)
def c(s):return ''.join(sum(([h,h,h]for h in[k for k,g in itertools.groupby(s)]),[]))
def v(s):
 while len(s)>=2 and s[-2]==s[-1]:s=s[:-1]
 return s+s[-1]+s[-1]
def a(n):
 for w in n.split():
  if r:r+=' '
  for i,s in enumerate(ss):
   r+=[v(s),s][any(j(t) for t in ss[i+1:])]if j(s)else[s,c(s)][i>0]
 return r

Test with:

while True:
 print a(raw_input('> '))
  • \$\begingroup\$ Shouldn't you at least golf it down further a little by removing unnecessary spaces and changing ss to S? \$\endgroup\$ – Adalynn Jul 21 '17 at 19:11

Python 3, 238 bytes

def f(s):
 s=s.upper();k=[s[0]];s=''.join(k+[s[i]for i in range(1,len(s))if s[i]!=s[i-1]])
 for i in range(1,len(s)):k+=[s[i]]*(3-2*(s[i]in'AEIOU'and i!=max(map(s.rfind,'AEIOU'))))
print(' '.join(map(f,input().split())))

Try it online!

  • \$\begingroup\$ Can you save bytes by setting v to 'AEIOU'? \$\endgroup\$ – Adalynn Jul 20 '17 at 20:33
  • \$\begingroup\$ @Zacharý Thanks, but unfortunately it doesn't change the bytecount. \$\endgroup\$ – hyper-neutrino Jul 20 '17 at 20:34
  • \$\begingroup\$ Oh, the spaces around the first v. \$\endgroup\$ – Adalynn Jul 20 '17 at 20:37

Perl 5, 139 + 1 (-p) = 140 bytes

$_=uc,s/^([^AEIOU]*)//,$s=$1,s/([^AEIOU])\1*/$1x(($q=length$&)>3?$q:3)/ge,s/.*?\K([AEIOU])\1*/$1x(($q=length$&)>3?$q:3)/e,print"$s$_ "for@F

Try it online!

Even handles the "aaaabbbbc" test case in accordance with the example.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.