15
\$\begingroup\$

Vowels rhyme: Apples and Bananas

There is a traditional children's song that repeats the same text over and over, only each time every vowel is replaced with a random vowel, but constant across the current stanza.

Challenge

The objective is to propose the shortest code that performs such a transformation on an input text.

Rules

  1. You must print the rhyme as many times as there are distinct vowels in it.
  2. Each print must be separated with a line break (platform-specific combo of \n and \r is accepted).
  3. For iteration i, replace each vowel with the ith distinct vowel in the original text.
  4. The input text is a sequence of printable ASCII characters (range [32, 126].
  5. Input will not contain embedded line breaks.
  6. Only vowels characters must be affected, other must be output exactly as input.
  7. Only vowels characters count: nasal vowels, although sounding like vowels (like in French "Tintin"), must not be handled as a single vowel.
  8. Case matters for the output, but is positional (replacing an uppercase vowel is done with the uppercase replacement vowel)
  9. Uppercase vowels are not distinct from their lowercase counterpart (ie a <=> A)
  10. Consecutive vowels are always considered separately (ie. Boat yields both Boot and Baat)
  11. Since the letter y represents either a vowel or consonant soun (as we're speaking English), handling it as a vowel or a consonant is allowed, however answers must explicitly state whether they handle y as a vowel or not.

Examples:

Hello world

Hello world!

gives:

Helle werld!
Hollo world!

Excerpt from the original French text (translated), with y handled as a vowel:

An elephant that was rambling all gently in the woods...

gives:

An alaphant that was ramblang all gantla an tha waads...
En elephent thet wes rembleng ell gentle en the weeds...
In iliphint thit wis rimbling ill gintli in thi wiids...
Yn ylyphynt thyt wys rymblyng yll gyntly yn thy wyyds...
On olophont thot wos romblong oll gontlo on tho woods...

Note the behaviour on leading uppercase vowel: case is kept at its index (rules 8 and 9).

Vowelless example

Input that does not contain any vowel, like:

lgn@hst:~$ rm -rf ./* ~ /

must produce no output, or a single line break.

Single-vowel input

Input containing a single vowel is output as is.

Dad sat at a car and saw a fat bat.

gives:

Dad sat at a car and saw a fat bat.

This is , so fewest bytecount code wins (nothing but eternal PPCG glory)!

\$\endgroup\$

14 Answers 14

6
\$\begingroup\$

Retina, 45 bytes

~(K`A\EI\OU
L$`\\?(.)
./$1/i&$*\T`Vv`5*$&$L$&

Try it online! Does not count y as a vowel. Explanation:

K`A\EI\OU

Replaces the text with the literal string A\EI\OU.

L$`\\?(.)

Matches each letter optionally preceded by a backslash.

./$1/i&$*\T`Vv`5*$&$L$&

Outputs a line of Retina code for each letter.

~(

Evaluates the generated code (shown below) using the original input. The . causes the code not to output the (final) buffer. The /<vowel>/i& causes the rest of the line to run only if the input contains the given vowel (case-insensitively). The * causes the result of the line to be ignored, so that the next vowel can be tested. The \ causes the result to be printed on its own line before it is ignored. The T`Vv`AAAAAa transliterates uppercase Vowels to AAAAAs and all lowercase vowels to a. \A is an escape that refers to ASCII 07 (BEL), but E, O and o are built-in character classes that needs to be escaped to give their literal values (e is not a character class, but fortunately it is also not an escape.)

./A/i&*\T`Vv`AAAAAa
./E/i&*\T`Vv`\E\E\E\E\E\e
./I/i&*\T`Vv`IIIIIi
./O/i&*\T`Vv`\O\O\O\O\O\o
./U/i&*\T`Vv`UUUUUu
\$\endgroup\$
  • \$\begingroup\$ Mmh, self-generating code. I don't know Retina well but that's impressive! \$\endgroup\$ – joH1 Sep 2 '18 at 18:57
  • \$\begingroup\$ @joH1 Well, for me the impressive bit is that it saved 60 bytes! \$\endgroup\$ – Neil Sep 2 '18 at 19:19
5
\$\begingroup\$

Ruby, 78 bytes

->s{s.downcase.scan(/[aeiou]/).uniq.map{|v|s.tr"AEIOUaeiou",v.upcase*5+v}*?\n}

Try it online!

A quick and naive approach. Y is not considered a vowel.

\$\endgroup\$
4
\$\begingroup\$

bash, 96 bytes

Two equal-length solutions:

v=aeiouAEIOU;for x in `grep -o [$v]<<<$1|sed 's/./\L&&&&&\U&/'|awk !a[\\$0]++`;{ tr $v $x<<<$1;}
v=aeiouAEIOU;for x in `tr -cd $v<<<$1|sed 's/./\L&&&&&\U&\n/g'|awk !a[\\$0]++`;{ tr $v $x<<<$1;}

Try it online!

Takes input as a command line argument and outputs to STDOUT.

\$\endgroup\$
4
\$\begingroup\$

05AB1E (legacy), 19 bytes

(Indirectly) saved one byte thanks to Kevin (printing directly inside the loop rather than joining, only work in the legacy version).

lžMÃÙεžMDu«s5×Du«‡=

Try it online!

Using the Elixir rewrite, 20 bytes

lžMÃÙεžMDu«s5×Du«‡}»

Try it online! (without y) | Try it online! (with y, žM being replaced by žO – same applies for the legacy version)

How it works

lžMÃÙεžMDu«s5×Du«‡}»     Full program. Example: "Hello"
l                        Convert the input to lowercase. "Hello" –> "hello"
 žMÃ                     Keep only lowercase vowels. "hello" –> "eo"
    Ù                    Remove duplicates. "eo" –> "eo"
     ε            }      For each of the characters (example with "e"):
      žMDu«              Yield "aeiouAEIOU"
           s5×           Swap, and repeat the current char 5 times. "e" –> "eeeee"
              Du«        Duplicate, uppercase and merge. "eeeee" –> "eeeeeEEEE"
                 ‡       Transliteration. For each item in B, replace it in A with
                         the corresponding item in C.
                   »     Join on newlines.
\$\endgroup\$
  • \$\begingroup\$ Nice answer, shorter than the 21 byte answer I prepared. You can golf one more byte by looping and printing instead of mapping: 19 bytes. Your TIO with y should also use 6 instead of 5, btw. \$\endgroup\$ – Kevin Cruijssen Sep 3 '18 at 9:17
  • \$\begingroup\$ @KevinCruijssen Edited, thanks! About the y-vowel version, I accidentally copied the wrong TIO link when I answered :|... \$\endgroup\$ – Mr. Xcoder Sep 3 '18 at 9:22
  • \$\begingroup\$ Ah, now I know again why I had the i in my code.. Your answer fails for inputs without vowels. Expected is an empty output, but it actually prints the input itself.. :( \$\endgroup\$ – Kevin Cruijssen Sep 3 '18 at 9:31
  • 1
    \$\begingroup\$ @KevinCruijssen The 20-byter works, so I rolled back and fixed the second link. \$\endgroup\$ – Mr. Xcoder Sep 3 '18 at 9:34
4
\$\begingroup\$

Japt v2.0a0 -R, 24 22 bytes

Treats y as a vowel. Change both occurences of \y to \v to treat it as a consonant.

v f\y â £r\y_Xc^H*ZøZu

Try it


Explanation

v                          :Lowercase
   \y                      :RegEx /[aeiouy]/gi (\v is /[aeiou]/gi)
  f                        :Get all matches as an array
      â                    :Deduplicate
        £                  :Map each X
         r\y               :  Replace all matches of the RegEx above in the input
             _             :  Pass matches through a function as Z
              Xc^          :    XOR the character code of X with
                 H*        :     32 multiplied by
                   Zø      :     Does Z contain
                     Zu    :      Uppercase Z
                           :Implicitly join with newlines and output
\$\endgroup\$
3
\$\begingroup\$

Jelly,  23 20 18  17 bytes

-2 Thanks to Erik the Outgolfer

ØcŒHZx5fƇðØc,yð€Y

To treat y as a vowel replace both cs with ys.

Try it online!

How?

ØcŒHZx5fƇðØc,yð€Y - Link: list of characters, S
Øc                - vowels -> "AEIOUaeiou"
  ŒH              - split in half -> ["AEIOU", "aeiou"]
    Z             - transpose -> ["Aa", "Ee", "Ii", "Oo", "Uu"]
     x5           - times 5 -> ["AAAAAaaaaa", "EEEEEeeeee", "IIIIIiiiii", "OOOOOooooo", "UUUUUuuuuu"]
        Ƈ         - filter keep if:
       f          -   filter keep only -> those of X which have required vowels
                  -                       ...i.e. if S = "blah" then ["AAAAAaaaaa"]
         ð    ð€  - dyadic chain for €ach:
          Øc      -   vowels -> "AEIOUaeiou"
            ,     -   pair       e.g. ["AEIOUaeiou","AAAAAaaaaa"]
             y    -   translate  e.g. swap A for A, E for A, ...
                Y - join with newlines
\$\endgroup\$
  • \$\begingroup\$ 18 bytes (trivial) (ż/ on a pair is Z, two dyads in a row where the left one is unpaired in a monad have the argument in-between implicitly) \$\endgroup\$ – Erik the Outgolfer Sep 2 '18 at 19:40
  • \$\begingroup\$ Thanks (Z >_<), not sure what was going on with my TIO session, but removing the redundant ð wasn't working; restart fixed. \$\endgroup\$ – Jonathan Allan Sep 2 '18 at 19:54
  • \$\begingroup\$ TBH, I actually fixed x€x too, but you ninja'd me. :P \$\endgroup\$ – Erik the Outgolfer Sep 2 '18 at 19:55
3
\$\begingroup\$

Red, 229 bytes

Taking y for a non-vowel

func[s][v: charset"aoeiu"w: charset"AOEIU"p: copy""parse s[any[[copy c[v | w](if not find p c[append p c lowercase c
parse s[any[[copy n to[v | w | end]](prin n)opt[v(prin c)|[w(prin uppercase copy c)]| skip]]]print""])]| skip]]]

Try it online!

Slightly more readable:

f: func [ s ] [
    v: charset "aoeiu"
    w: charset "AOEIU"
    p: copy ""
    parse s[ 
        any [
            [ copy c [ v | w ]
                ( if not find p c [ 
                    append p c
                    lowercase c
                    parse s [
                        any [
                            [ copy n to [ v | w | end ] ]
                                 ( prin n )
                            opt [ v ( prin c )
                                | [ w ( prin uppercase copy c ) ]
                                | skip
                                ]
                            ] 
                        ]
                    print ""
                ] )
            ]
            | skip
        ]
    ]
]
\$\endgroup\$
3
\$\begingroup\$

R, 138, 129 bytes

function(x,U=utf8ToInt,a=U(V<-'aeiouAEIOU'))for(i in (which(a%in%U(x))-1)%%5)cat(chartr(V,intToUtf8(rep(a[i+c(1,6)],e=5)),x),'
')

Try it online!

  • y is not considered a vowel
\$\endgroup\$
2
\$\begingroup\$

Python, 129 119 112 bytes

import re
f=lambda s:'\n'.join(r('[AEIOU]',v.upper(),r('[aeiou]',v,s))for v in'aeiou'if v in s.lower());r=re.sub

Try it Online!

Doesn't treat \$y\$ as vowel.

-7 bytes thanks to @Mr.Xcoder

\$\endgroup\$
  • \$\begingroup\$ Glad to see you could get it working and golfed down a bit! Nice work \$\endgroup\$ – joH1 Sep 2 '18 at 20:34
  • \$\begingroup\$ 112 bytes. \$\endgroup\$ – Mr. Xcoder Sep 2 '18 at 21:53
2
\$\begingroup\$

JavaScript (Node.js), 99 bytes

Treats \$y\$ as a consonant.

s=>(g=F=>Buffer(s).map(c=>2130466>>c&c>64?F(c):c)+`
`)(v=>g[v&=31]||(g[v]=S+=g(c=>c&96|v)),S='')&&S

Try it online!

Commented

s => (                   // s = input string
  g = F =>               // g = helper function taking a callback function F
    Buffer(s)            // turn s into a Buffer
    .map(c =>            // for each ASCII code c in s:
      2130466            //   2130466 is a vowel bitmask: 1000001000001000100010
                         //                               u     o     i   e   a
      >> c               //   the ECMAScript specification enforces that the shiftCount is
                         //   the result of masking out all but the least significant 5 bits
      & c > 64           //   also make sure to ignore non-letter characters
      ?                  //   if a vowel is identified:
        F(c)             //     invoke F with c
      :                  //   else:
        c                //     just yield c
    ) + `\n`             // end of map(); coerce back to a string and append a newline
  )(v =>                 // invoke g with a callback that takes v:
    g[v &= 31] || (      //   unless this vowel has already been encountered:
      g[v] =             //     mark it as encountered
      S +=               //     and append to the output string S
      g(                 //     the result of another call to g:
        c => c & 96 | v  //       where vowels are replaced with v, using the original case
      )                  //     end of inner call to g
    ),                   //
    S = ''               //   start with S = ''
  ) && S                 // end of outer call to g; return S
\$\endgroup\$
2
\$\begingroup\$

Java 10, 196 188 bytes

s->{var d=new int[99];for(var c:s.toUpperCase().replaceAll("[^AEIOU]","").toCharArray())if(d[c]++<1)System.out.println(s.replaceAll("[AEIOU]",c+"").replaceAll("[aeiou]",(char)(c+32)+""));}

-8 bytes thanks to @joH1.

Without y as vowel to save bytes.

Try it online.

Explanation:

s->{                       // Method with String parameter and no return-type
  var d=new int[99];       //  Integer-array indicating which vowels we've already output
  for(var c:s.toUpperCase()//  Convert the input to uppercase
            .replaceAll("[^AEIOU]","")
                           //  Remove all non-vowels
            .toCharArray())//  Convert it to a character array)
                           //  And loop over those vowel-characters
    if(d[c]++              //   Increase the vowel-count by 1
             <1)           //   And if it was 0 this iteration:
      System.out.println(  //    Print with trailing newline:
        s                  //     The input,
         .replaceAll("[AEIOU]",c+"")
                           //     with every uppercase vowel replace with the current vowel
         .replaceAll("[aeiou]",(char)(c+32)+""));}
                           //     and every lowercase vowel replaced as well
\$\endgroup\$
  • \$\begingroup\$ 188 bytes by inlining the variable v in the loop \$\endgroup\$ – joH1 Sep 4 '18 at 9:03
  • \$\begingroup\$ @joH1 Thanks, not sure how I missed that.. \$\endgroup\$ – Kevin Cruijssen Sep 4 '18 at 9:07
1
\$\begingroup\$

Python 2, 112 bytes

s=input()
V='aeiouAEIOU'
for v in V:
 if v in s.lower():print''.join([c,[v.upper(),v][c>'Z']][c in V]for c in s)

Try it online!

Treats y as a consonant.

\$\endgroup\$
1
\$\begingroup\$

Perl 6, 64 bytes

{m:g:i/<[aeiou]>/».lc.unique».&{$^v;say S:g:ii[<[aeiou]>]=$v}}

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Java (OpenJDK 8), 184 bytes

y is a vowel

s->s.chars().mapToObj(c->""+(char)(c>96?c:c+32)).filter("aeiouy"::contains).distinct().forEach(c->System.out.println(s.replaceAll("[aeiouy]",c).replaceAll("[AEIOUY]",c.toUpperCase())))

Try it online!

\$\endgroup\$

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.