When babies open their mouths, they're not just spewing gibberish. They're actually talking in a highly advanced, adult-proof cipher...

The Baby-talk Cipher

When a baby talks, it could look something like gogooa gagooook aagaaoooy Each single-space separated section represents a character (so the example above represents 3 characters).

To decipher a section, we must count number of As and Os it contains. However, we only count those which are adjacent to another vowel. For example, the A in 'gag' would not count, but both the A and O in 'gaog' would.

Counting the example above would look like this:

Section    | Num Os | Num As

gogooa     | 2      | 1
gagooook   | 4      | 0
aagaaoooy  | 3      | 4

We then use these values to convert the input into plaintext on a Polybius square. This is a 5x5 representation of the English alphabet, omitting 'J' (please note that, in baby-talk, 0-counting rules apply to the table):

  0 1 2 3 4
0 A B C D E
1 F G H I K
2 L M N O P
3 Q R S T U
4 V W X Y Z

Using the number of Os as the column, and number of As as the row, we find which character each section represents:

Section    | Num Os | Num As | Character

gogooa     | 2      | 1      | (2,1) -> H
gagooook   | 4      | 0      | (4,0) -> E
aagaaoooy  | 3      | 4      | (3,4) -> Y

Which tells us that the baby was just saying "HEY".

- If a section representing a character has more than 4 As or Os, ignore the extras, because 4 is the maximum value on the table. - For this task, Y is not a vowel - only A, E, I, O and U.

The Challenge

Your task is to create a full program which takes one input, a word in baby-speak, and prints it in plaintext.

  • Your program must be able to take input in uppercase, lowercase, and a mix of both.
  • The input will only contain ASCII alphabet letters (A-Z and a-z), with single spaces to seperate the baby words.
  • The output text can be in any case.
  • You should the take the input from STDIN and print the plaintext on STDOUT. If your language does not have these, use the nearest equivalent.
  • This is , so the shortest code in bytes wins - but any solution is welcome.

Test Cases

'oaka pooopaa gaau augu' -> GOLF
'Aoao U oOOAoa oaoAoo aoAoAOa' -> NAPPY
'GUG gAGaA gOougOou' -> ALE
  • 3
    \$\begingroup\$ 'GUG gAGaA gOougOou' -> 'ALE' Babies drink ale? :D \$\endgroup\$
    – user41805
    Nov 1, 2016 at 7:31
  • 7
    \$\begingroup\$ only the finest :D @KritixiLithos \$\endgroup\$
    – FlipTack
    Nov 1, 2016 at 8:08
  • 1
    \$\begingroup\$ The case requirement seems unnecessary, right? All you're doing is adding a .toUpperCase() or similar function call, not an actually stimulating challenge \$\endgroup\$
    – bren
    Nov 1, 2016 at 12:45
  • 1
    \$\begingroup\$ How does gogooa have 2 o's? And how does gagooook have 0 a's? \$\endgroup\$ Nov 1, 2016 at 13:57
  • 1
    \$\begingroup\$ Actually, @EriktheGolfer , that's FAG :P \$\endgroup\$
    – FlipTack
    Nov 6, 2016 at 12:13

16 Answers 16


Perl, 82 bytes

Includes +1 for -a

Give input on STDIN:

perl -M5.010 baby.pl <<< "OOaGOG GoGOOoGoU gAA bLAA GOUGoOUgAIGAI"


#!/usr/bin/perl -a
say map{$A=$O=$_=uc;y/AEIOU/@/c;s/(\B.|.\B)/$$1+=$$1<4/eg;(A..I,K..Z)[5*$A+$O]}@F

This assumes a recent enough perl version where -a implies -n. If your perl is too old you will need to add an explicit -n option.

It also assumes babies can't say general ASCII strings that start with digits like 1 this will not work

  • \$\begingroup\$ that's a correct assumption. I'll make sure to specify that in the question \$\endgroup\$
    – FlipTack
    Nov 1, 2016 at 20:33

05AB1E, 46 bytes


Try it online!

Explanation in steps

  1. split on spaces to form words
  2. replace konsonants in words with spaces
  3. split words on spaces to form groups of vowels
  4. remove vowel groups with a length shorter than 2
  5. get min of count(a) and 4, multiply by 5
  6. get min of count(o) and 4
  7. add counts
  8. get letter at that index of alphabet (excluding "j")
  • \$\begingroup\$ Good job, congrats on winning \$\endgroup\$
    – FlipTack
    Nov 7, 2016 at 16:14
  • \$\begingroup\$ I like the approach of splitting by consonants, I didn't think of that \$\endgroup\$
    – FlipTack
    Nov 7, 2016 at 17:00

brainfuck, 656 bytes


This was a pretty good way to kill a couple of hours.

Requires a brainfuck interpreter that uses 8-bit wrapping cells, allows you to go left from cell 0 and returns 0 if , is used when stdin is empty. In my experience, these are the most common settings.

This program does not consider Y a vowel, but if OP wants it to it's an easy fix.

It seems like writing this would be a daunting task but if you have some familiarity with the language there's nothing surprising or new in the code. Standard brainfuck tactics: Read the input but make sure you leave a couple of empty cells between each byte, use those empty cells to store data about the input, use the data you stored to decide how to transform it and spit something out at the end. In this case it was get the input, set it all to uppercase, figure out which cells are vowels, throw that information away after using it to determine which cells are next to vowels, set everything that isn't next to a vowel to some value that will never be relevant so they're not in the way later, and you're basically done. From there you just have to count your As and Os, multiply As by 5 and add the number of Os, special case anything above 8 to avoid J and output. I did choose to handle this one word at a time, rather than taking the whole input at once, so I had to set up the part of the code that reads stdin to break at 0 or 32, but that's not too big of a problem (just wrap the subtraction by 32 in a conditional so it doesn't happen if the value is already 0, then correct for any < or > instructions you missed later).

I don't know how helpful it will be because I wrote it mostly to keep my thoughts straight rather than as a real explanation, but here's the code with my comments and its original indentation:

+[[>>>,[>++++[<-------->-]]<]get an entire word of input
                            each character lowered by 32
                            two empty cells between characters
                            stops when reaching a space or null byte

any lowercase letters have become uppercase; anything with a value below 65 used
to be an uppercase character; fix it

<<[>]<-[+                for each character until hitting 1:
  [<+>>+<-]              make a backup
  subtract 64 from the character but stop if it hits 0
  ----[>>+<<----]>>+     generate the number 64
  [                      64 times:
    <[                     if the character is not 0:
      -                    subtract 1
      <                    go to a guaranteed 0 cell to break the loop
    we're either on the character or to the left of it; sync up
  -<[[-]>+<]>            logical NOT of character
  [                      if logical NOT returns true:
    [-[->]<<+>]<-          add 32 to backup of character
  <<<[>>>+<<<-]          move copy over to make room
  >>>>>[                 for each character:
  [<+>>+<-]              make copies
  ----[>-<----]>--       check if it's A
  [----<]<[>]>           check if it's E
  [----<]<[>]>           check if it's I
  [------<]<[>]>         check if it's O
  [------<]<[>]>         check if it's U
  <+>[[-]<->]            logical NOT to complete vowel check

<<<[                if the last char is a vowel; prevent a side effect

<[<]>[                 for each character:
  >[                     if it's a vowel:
    <<<<<+>>>>>>+<-          leave a flag to the left and right to show that a
  ]                          vowel is adjacent

<[-]>                  clean up a side effect left behind if first char is vowel

>>>[                   for each char:
  <[                     if it's adjacent to a vowel:
    >[>+<-]<-              move it to the side
  >[-]-                otherwise; destroy it
  >[<+>-]              move backup over if it exists (subtracting 1)

all characters without a vowel beside them have been set to 255
all characters with a vowel beside them are set to itself minus 1

notable charaters are: 'A' minus 1 = 64
                       'O' minus 1 = 78

<<<[                 for each character:
  -<----[>-<----]      subtract 64
  >[>+>+<<-]           make a copy
  +>[<->[-]<]<[<]>     logical NOT
  [[<<<]<+>>>>[>>>]<<<-] if NOT returns true; record an A
  >+>--------------  subtract 14 from backup
  [<->[-]]<          logical NOT
  [-<<<<[<<<]>+>>[>>>]>] if NOT returns true; record an O

<[<+<+>>-]           make a backup of A count
>++++[<<[->]>[<]>-]  subtract 4 but don't go below 0
+<<[                   if the char was greater than 3:
  [-]++++<[-]>>          put 4 there
>[<]                  resynchronise
<<[>+<-]              if there were fewer than 4 As put the number back

same thing but for the O count

>>+>->[>+>+<<-]       make a backup of O count
<++++[>>[-<]<[>]<-]   subtract 4 but don't go below 0
>>[                     if the char was greater than 3:
  [-]++++>[-]             put 4 there
<<<[>]                resynchronise
<->>>>[<+>-]          if there were fewer than 4 Os put the number back

<[<<<+>>>-]<<<<[>+++++<-] A*5 plus B = index of character to output

>[>+>+<<-]            make a backup
<++++++++[>>[-<]<[>]<-] subtract 8 but don't go below 0
>>[[-]>+<]            if the result is nonzero it is late enough in the alphabet
                      that it must be increased by 1 to exclude J as a possible
----[>+<----]>++      add 65 to make it a letter
.[-]+>>>,             output and get new input
[<++++[>--------<-]]> sub 32 if not 0
  • \$\begingroup\$ This is amazing... and yes, by vowels I meant a,e,i,o,u :) \$\endgroup\$
    – FlipTack
    Nov 1, 2016 at 19:56

JavaScript (ES6), 145 bytes

alert(prompt().replace(/\S+ ?/g,x=>(g=r=>(q=(x.match(/[aeiou]{2,}/gi)+"").split(r).length-1)>4?4:q,(g(/a/i)*5+g(/o/i)+10)*20/19|0).toString(36)))

Replaces each word (and the following space) with its corresponding letter.

s.split` `.map().join`` is 3 bytes longer:

alert(prompt().split` `.map(x=>(g=r=>(q=(x.match(/[aeiou]{2,}/gi)+"").split(r).length-1)>4?4:q,(g(/a/i)*5+g(/o/i)+10)*20/19|0).toString(36)).join``)
  • \$\begingroup\$ The challenge currently states that you should write "a full program which takes input [from STDIN] and prints it [to STDOUT]." This means that as currently written function answers aren't allowed. \$\endgroup\$
    – CAD97
    Nov 1, 2016 at 16:11
  • \$\begingroup\$ Nice submission, but as CAD said, it has to be a full program. I'm not very familiar with JavaScript but I think prompt and alert are the best equivalents to STDIN/OUT, right? \$\endgroup\$
    – FlipTack
    Nov 1, 2016 at 20:14
  • \$\begingroup\$ @Flp.Tkc Yeah, unless you're using Node or some other environment. I'll update my code. \$\endgroup\$ Nov 1, 2016 at 20:15
  • \$\begingroup\$ the question does say or the nearest equivalent. For js in the browser, a prompt and alert are close enough \$\endgroup\$
    – coagmano
    Nov 7, 2016 at 7:35

Perl, 159 +1 = 160 bytes

+1 byte for -n flag. Whitespace is not part of the code and is only provided for readability.

    $b++until$b>$#a||$a[$b]eq o;

The code splits the input by spaces and converts each baby word to lowercase before proceeding. The regex finds all a or o vowels that are followed by another vowel, or are preceeded by a vowel, and sorts them, a's at the start, o's at the end, then finds the index of the first 'o'. If the remaining number of matches (aka, the number of 'a's) is greater than 4, then we care about 4 a's, and if there are more than 4 o's, we care about 4 o's. Then it pulls the appropriate letter out of the matrix and prints it, then moves onto the next baby word.


Brainfuck, 283 bytes



        not a
          not e
            not i
              not o
      >[>>>>+<<<<-]> >+<
        prev was vowel

This works with or without a trailing newline in the input.

Try it online.

Each character is processed mod 32 (with control flow such that the code implementing the mod operation only occurs once in the program). This enables case insensitivity, as well as collapsing the space character and EOF into a single case. A trailing newline is treated the same as J, which doesn't affect the output.

Sketch of memory layout:

0 x C c y a A b B

where c is the input character, C is the char mod 32, x is whether it is a vowel, y is whether the previous char was a vowel, A and B are the counts of valid (next to vowels) a and o chars respectively, and a and b are their respective buffers that get copied or cleared depending on whether there is an adjacent vowel.

When a space or EOF is reached, some juggling is done to reduce counts greater than 4 and to skip the letter J, and then the decoded character is printed.

  • \$\begingroup\$ this is very close to the java implementation in byte count ... hats off to you \$\endgroup\$
    – hstde
    Nov 7, 2016 at 8:36
  • \$\begingroup\$ it's a crime that this has less points than my trivial solution that's over twice as long \$\endgroup\$ Dec 2, 2016 at 0:43
  • \$\begingroup\$ @undergroundmonorail That makes me an accomplice! \$\endgroup\$ Dec 12, 2016 at 18:04

PHP, 163 bytes

<?php for(;$c=preg_replace('/(?<![AEIOU]).(?![AEIOU])/','',strtoupper($argv[++$i]));$j=min($d[79],4)+5*min($d[65],4),print range(A,Z)[$j+($j>8)])$d=count_chars($c);

More readable version:

for (
    $c = preg_replace(
    $j = min($d[79], 4) + 5 * min($d[65], 4),
    print range(A, Z)[$j + ($j > 8)]
    $d = count_chars($c);


$ php babytalk.php oaka pooopaa gaau augu
$ php babytalk.php Aoao U oOOAoa oaoAoo aoAoAOa
$ php babytalk.php GUG gAGaA gOougOou
$ php babytalk.php OOaGOG GoGOOoGoU gAA bLAA GOUGoOUgAIGAI

Java 8, 272 266 251 249 bytes

interface M{static void main(String[]i){String z="(?=[AEIOU])|(?<=[AEIOU])";for(String s:i[0].split(" ")){int a=s.split("(?i)A"+z+"A",-1).length-1,o=s.split("(?i)O"+z+"O",-1).length-1,t=(a>4?4:a)*5+(o>4?4:o);System.out.printf("%c",t>9?t+66:t+65);}}}

-6 bytes thanks to @Joba.
-1 byte converting from Java 7 to 8, and 14 16 additional bytes saved by changing the print-part.


Try it here.

interface M{                   // Class:
  static void main(String[]i){ //  Main method:
    String z="(?=[AEIOU])|(?<=[AEIOU])";
                               //   Regex-part for look-ahead or look-behind of vowels
    for(String s:i[0].split(" ")){  
                               //    Loop over the program-arguments
      int a=s.split("(?i)A"+z+"A",-1).length-1,
                               //     The amount of A's with adjacent vowels
                               //     The amount of O's with adjacent vowels
          t=(a>4?4:a)          //     If `a` is larger than 4, just take 4, else take `a`
            *5                 //     Multiply it by 5
            +(o>4?4:o);        //     And add 4 if `o` is larger than 4, else take `o`
       System.out.printf("%c", //     Print a character:
        t>9?                   //      If `t` is larger than 9 (index of J)
         t+66                  //       Take character unicode (skipping J)
        :                      //      Else:
         t+65);                //       Take character unicode (prior to J)
    }                          //   End of loop
  }                            //  End of main-method
}                              // End of program
  • 1
    \$\begingroup\$ The challenge currently states that you should write "a full program which takes input [from STDIN] and prints it [to STDOUT]." This means that as currently written function answers aren't allowed. \$\endgroup\$
    – CAD97
    Nov 1, 2016 at 16:11
  • \$\begingroup\$ @CAD97 Thanks, read past that somehow. I've edited my answer accordingly. \$\endgroup\$ Nov 1, 2016 at 18:02
  • 1
    \$\begingroup\$ Instead of using the upper case string, add the case invariant regex flag (?i) at the beginning of the s.split \$\endgroup\$
    – Joba
    Nov 7, 2016 at 12:19

Python 3, 163 162 157 146 bytes

import re
for W in input().upper().split():S=''.join(re.findall("[AEIOU]{2,}",W)).count;I=min(S('A'),4)*5+min(S('O'),4);print(end=chr(65+I+(I>9)))

Uses regex to find all string of vowels larger than 2, counts As and Os with maximum of 4, and then prints.


APL, 60

{⎕A[a+9<a←5⊥+/¨'ao'∊⍨¨⊂⍵/⍨0(,∨,⍨)2∧/⍵∊'aeiou']}¨' '(≠⊂⊢)819⌶

Note that ⎕IO←0 and ⎕ML←3


fn←{⎕A[a+9<a←5⊥+/¨'ao'∊⍨¨⊂⍵/⍨0(,∨,⍨)2∧/⍵∊'aeiou']}¨' '(≠⊂⊢)819⌶
fn 'Aoao U oOOAoa oaoAoo aoAoAOa'

Works in Dyalog 15.0, since it's the version in which 819⌶ was introduced to lowercase a string.

  • \$\begingroup\$ Are you sure you dropped the J and not the K? \$\endgroup\$
    – FrownyFrog
    Oct 11, 2017 at 23:32

Pyth, 64 bytes

Can probably be golfed further. Try it here !


R, 261 bytes

I think I spent way too much time just to get this working and I believe this is an unnecessarily complicated solution, although it works. Takes input from stdin, it's important that the string is enclosed in quotes.

x=el(strsplit(toupper(scan(,""))," "))

The use of four nested apply-family could theoretically be reduced to only two by making use of mapply instead. But because inputs to mapply will not be of the same length, the shorter one is recycled which complicates things and I couldn't figure out a working solution.

If anyone is interested I'll add an ungolfed explanation later.

Try all the test cases on R-fiddle

Please note that this version takes input as a function argument instead from stdin because scan doesn't work on R-fiddle. Furthermore, added a newline to make it easier to read.


Python 3, 262 bytes

import re;f,b,v,n,r,l,t,g,a,o=re.findall,input().lower(),'aeiou',list(range(26)),'[aeiou]','abcdefghiklmnopqrstuvwxyz','',len,'a','o';del n[9],
for w in b.split():
 if O>4:O=4
 if A>4:A=4

Less Golfed (The comments are the variables in the shortened code):

import re
findAll = re.findall #f
babyTalk = input('Baby Talk: ').lower() #b
vowels = 'aeiou' #v
numbers = list(range(26)) #n
del numbers[9]
letters = 'abcdefghiklmnopqrstuvwxyz' #l
finalText = '' #t
length = len #g
regex = '[aeiou]' #r
o = 'o' #o
a = 'a' #a
for word in babyTalk.split(): #w in b
 Os = len(findAll('o[aeiou]', word)) + len(findAll('[aeiou]o', word)) #O
 As = len(findAll('a[aeiou]', word)) + len(findAll('[aeiou]a', word)) #A
 if Os > 4: Os = 4
 if As > 4: As = 4
 print(As, Os)
 finalText += letters[As*5+Os]

Try it online!

  • \$\begingroup\$ This doesn't work for a word blaoaoaog: the interlaced vowels are counted more than once, giving z when it should be t (though it does work on just aaaooo, though I cannot figure out why....) \$\endgroup\$
    – CAD97
    Nov 2, 2016 at 1:13
  • \$\begingroup\$ @CAD97 Are you saying that aooa should be p, not n? \$\endgroup\$
    – nedla2004
    Nov 2, 2016 at 1:50
  • \$\begingroup\$ not on purpose; aooa == (2,2) == n, aoaoao == (3,3) == t \$\endgroup\$
    – CAD97
    Nov 2, 2016 at 2:11
  • \$\begingroup\$ just tested it and CAD is correct, gaoaoaog prints Z instead of T. I think it's because your regex is picking up [ao,oa,ao,oa,ao], which counts 5,5, then constricts it to 4,4, printing Z. \$\endgroup\$
    – FlipTack
    Nov 2, 2016 at 20:48
  • \$\begingroup\$ @Flp.Tkc Do you know how to fix it? I am very new to regex. \$\endgroup\$
    – nedla2004
    Nov 2, 2016 at 22:21

Kotlin, 221 209 bytes

Now much more ugly and slow, all in the name of 11 bytes

readLine()!!.toLowerCase().split(" ").map{fun
c(c:Char)=Regex("([aeiou]{2,})").findAll(it).fold(0){a,b->a+b.value.count{it==c}}.let{if(it>4)4 else it}

Save it to a file (ex. BabyTalk.kts) to run as a script. Or, the above code can be prepended with fun main(z:Array<String>)= and compiled normally for a cost of 26 more bytes.

Try it online!


    .split(" ")
    .map {
        fun c(c: Char) =
                .fold(0) {
                    a, b ->
                    a + b.value.count { it == c }
                .let { if (it > 4) 4 else it }
        (('A'..'I') + ('K'..'Z'))[c('a') * 5 + c('o')]

PHP, 124 129 121 120 125 bytes

for(;$s=$argv[++$i];print chr((8<$O+=5*$A)+$O+65))for($k=$A=$O=0;$c=_&$s[$k++];$p=$c)$$c+=$$c<4&!trim($p.$s[$k]&__,AEIOU)[1];

Takes input from command line arguments. Run with -nr or try it online.


for(;$s=$argv[++$i];            # loop $s through arguments
    print chr((8<$O+=5*$A)+$O+65)   # 3. map A and O counts to letter, print
    for($k=$A=$O=0;                 # 1. reset A and O counters
        $c=$s[$k++]&_;              # 2. loop $c through characters:
        $p=$c)                          # 2. remember current character as previous
        $$c+=                           # 1. increment counter for $c, if ...
            $$c<4&                          # it is < 4 and ...
            !trim($p.$s[$k]&__,AEIOU)[1];   # ... previous or next char is vowel

J, 109 bytes

echo{&(u:97+i.26)(+8<[)5#.4<.'AO'+/@e."1 0/~(;@#~1<#@>)@(</.~0+/\@,}.~:&(e.&'AEOUI')}:);._1' ',toupper 1!:1]3

Try it online!


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.