ANNNOUNNNCCCEEERRR VOICCCEEE

18

1

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('> '))

Quuxplusone

Posted 2017-07-20T08:01:35.353

Reputation: 625

2A 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. – Dennis – 2017-07-21T15:51:27.427

It should be the vowels that are "elongated" :( – Devil's Advocate – 2017-07-21T19:56:28.437

What is consonant cluster? – MilkyWay90 – 2018-11-11T20:41:12.940

Answers

6

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)

Adám

Posted 2017-07-20T08:01:35.353

Reputation: 37 779

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⌶)⍞ – Zacharý – 2017-07-20T20:34:00.337

^ Saves two bytes if it works ^ – Zacharý – 2017-07-20T20:35:18.343

5

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.

ABot

Posted 2017-07-20T08:01:35.353

Reputation: 203

1"WAAAYYY TOOO MAAANNNYYY BYYYTTTEEESSSS" ... is in first place, ahead of APL. – Zacharý – 2017-07-20T20:49:34.367

I don't know JS, but can you replace s=>/[AEIOU]/.test(s) with /[AEIOU]/.test? – musicman523 – 2017-07-20T21:44:50.770

@musicman523 sadly, no, because it is the conditional in a ternary operator statement. – ABot – 2017-07-20T22:27:34.353

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). – Quuxplusone – 2017-07-20T22:47:01.457

Well, was in first place. – Zacharý – 2017-07-21T23:34:05.787

5

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)

marinus

Posted 2017-07-20T08:01:35.353

Reputation: 30 224

You beat Adám ... wow. – Zacharý – 2017-07-21T23:32:26.200

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⌶)⍞ – Gil – 2017-08-24T22:26:05.980

3

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('> '))

Quuxplusone

Posted 2017-07-20T08:01:35.353

Reputation: 625

Shouldn't you at least golf it down further a little by removing unnecessary spaces and changing ss to S? – Zacharý – 2017-07-21T19:11:37.107

2

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!

HyperNeutrino

Posted 2017-07-20T08:01:35.353

Reputation: 26 575

Can you save bytes by setting v to 'AEIOU'? – Zacharý – 2017-07-20T20:33:01.827

@Zacharý Thanks, but unfortunately it doesn't change the bytecount. – HyperNeutrino – 2017-07-20T20:34:32.110

Oh, the spaces around the first v. – Zacharý – 2017-07-20T20:37:05.303

0

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.

Xcali

Posted 2017-07-20T08:01:35.353

Reputation: 7 671