20
\$\begingroup\$

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
SUNNNDDDAAAYYY SUNNNDDDAAAYYY
> mia hamm
MIAAA HAAAMMM
> chester alan arthur
CHESSSTTTEEERRR ALLLAAANNN ARRRTTTHHHUUURRR
> attention please
ATTTENNNTTTIOOONNN PLEASSSEEE
> supercalifragilisticexpialidocious
SUPPPERRRCCCALLLIFFFRRRAGGGILLLISSSTTTICCCEXXXPPPIALLLIDDDOCCCIOUUUSSS
> moo
MOOO
> Aachen
AACCCHHHEEENNN
> Oooh
OOOHHH
> grifffest
GRIFFFEEESSSTTT
> k
K
> aaaabbbbc
AAAABBBBCCC

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):
 r=''
 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('> '))
\$\endgroup\$
3
  • 3
    \$\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
    Commented Jul 21, 2017 at 15:51
  • \$\begingroup\$ It should be the vowels that are "elongated" :( \$\endgroup\$ Commented Jul 21, 2017 at 19:56
  • \$\begingroup\$ What is consonant cluster? \$\endgroup\$
    – MilkyWay90
    Commented Nov 11, 2018 at 20:41

6 Answers 6

5
\$\begingroup\$

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)

\$\endgroup\$
2
  • \$\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
    Commented Jul 20, 2017 at 20:34
  • \$\begingroup\$ ^ Saves two bytes if it works ^ \$\endgroup\$
    – Adalynn
    Commented Jul 20, 2017 at 20:35
5
\$\begingroup\$

APL, 90 bytes

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

Explanation:

  • 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)
\$\endgroup\$
2
  • \$\begingroup\$ You beat Adám ... wow. \$\endgroup\$
    – Adalynn
    Commented Jul 21, 2017 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
    Commented Aug 24, 2017 at 22:26
4
\$\begingroup\$

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

Ungolfed

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.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ "WAAAYYY TOOO MAAANNNYYY BYYYTTTEEESSSS" ... is in first place, ahead of APL. \$\endgroup\$
    – Adalynn
    Commented Jul 20, 2017 at 20:49
  • \$\begingroup\$ I don't know JS, but can you replace s=>/[AEIOU]/.test(s) with /[AEIOU]/.test? \$\endgroup\$ Commented Jul 20, 2017 at 21:44
  • \$\begingroup\$ @musicman523 sadly, no, because it is the conditional in a ternary operator statement. \$\endgroup\$
    – ABot
    Commented Jul 20, 2017 at 22:27
  • 1
    \$\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\$ Commented Jul 20, 2017 at 22:47
  • \$\begingroup\$ Well, was in first place. \$\endgroup\$
    – Adalynn
    Commented Jul 21, 2017 at 23:34
2
\$\begingroup\$

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):
 r=''
 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

Test with:

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

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'))))
 return''.join(k)
print(' '.join(map(f,input().split())))

Try it online!

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

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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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