12
\$\begingroup\$

I have a string like this:

s = "helloworldandhellocodegolf"

I want to make every consonant after a vowel uppercase.

Desired output:

heLloWoRldaNdheLloCoDeGoLf

As you can see, l gets uppercased because it's right after the vowel e etc..

If there are repeated vowels, like:

s = "aabeekad"

Desired output:

s = "aaBeeKaD"

This is , so shortest code in bytes wins.

The consonants are all alphabet characters except for aeiou.

\$\endgroup\$
10
  • 2
    \$\begingroup\$ Is it guaranteed that the input consists only of letters? \$\endgroup\$ Dec 17, 2022 at 2:59
  • \$\begingroup\$ @dingledooper Yes. \$\endgroup\$ Dec 17, 2022 at 3:00
  • 4
    \$\begingroup\$ Is the input guaranteed to only be lowercase? The question doesn't specify, and almost all current answers fail with uppercase vowels \$\endgroup\$
    – jezza_99
    Dec 17, 2022 at 4:01
  • \$\begingroup\$ @jezza_99 Yes, lowercase. \$\endgroup\$ Dec 17, 2022 at 4:05
  • 3
    \$\begingroup\$ @mousetail There's already a footnote about that. (But it should probably be stated at the beginning.) \$\endgroup\$
    – Arnauld
    Dec 17, 2022 at 10:58

27 Answers 27

10
\$\begingroup\$

JavaScript (Node.js), 47 bytes

Expects and returns a string.

s=>Buffer(s).map(c=>c^s&~(s=68174912>>c)&32)+''

Try it online!

How?

The constant \$68174912\$ (which I've already used here) is a bitmask describing the positions of the vowels:

00000100000100000100010001000000
     v     v     v   v   v
zyxwvutsrqponmlkjihgfedcba`_^]\[

Commented

s =>           // s = input string
Buffer(s)      // turn it into a buffer
.map(c =>      // for each ASCII code c:
  c ^          //   toggle the case if
  s &          //   the previous letter was a vowel
  ~(           //   and the current letter is a consonant
    s =        //   save in s the new state obtained by
      68174912 //   right-shifting the bit-mask
      >> c     //   by c positions (mod 32)
  ) & 32       //   isolate the case bit
) + ''         // end of map(), coerce back to a string

JavaScript (ES6), 38 bytes

Expects and returns an array of ASCII codes.

a=>a.map(p=c=>c^p&~(p=68174912>>c)&32)

Try it online!

\$\endgroup\$
9
\$\begingroup\$

C (clang), 61 bytes

A full program that takes input from STDIN, and outputs to STDOUT.

c;main(d){for(;read(0,&c,1);)putchar(c^d-(d='Xz'%c>0)&32);}

Try it online!

I use the same formula to check for vowels as in this other task. Here, (d='Xz'%c>0) sets d equal to \$ 0 \$ if the current letter c is a vowel, and \$ 1 \$ otherwise. c should be uppercased if and only if the current d is \$ 1 \$, and the previous d is \$ 0 \$. To apply the uppercasing, c is XOR'ed with \$ 32 \$, but only when the conditions are met. Below is a table to visualize what is happening:

 | prev_d | d | prev_d - d | & 32 | ^ c  |
-+--------+---+------------+------+------+-
 |    0   | 0 |      0     |   0  |   c  |
 |    0   | 1 |     -1     |  32  | 32^c |
 |    1   | 0 |      1     |   0  |   c  |
 |    1   | 1 |      0     |   0  |   c  |
\$\endgroup\$
6
  • \$\begingroup\$ Nice. First answer using C. \$\endgroup\$ Dec 17, 2022 at 4:06
  • \$\begingroup\$ dingledooper, Does read(0,&c,1) only work when int is little endian? \$\endgroup\$ Dec 17, 2022 at 10:42
  • 1
    \$\begingroup\$ @chux-ReinstateMonica Probably. If we want to be more inclusive, ~(c=getchar()) works at the cost of a byte. \$\endgroup\$ Dec 17, 2022 at 22:42
  • \$\begingroup\$ I have checked using brute force, that there are 2 byte numbers which can be used, but they need to be compared against 2 digit numbers, so you can probably save one byte. \$\endgroup\$
    – Jiří
    Dec 20, 2022 at 21:05
  • \$\begingroup\$ @Jiří 36865%x>14 is the same length as 'Xz'%c>0. Unfortunately I couldn't find a way to compress 36865, or any of the other numbers you found. \$\endgroup\$
    – naffetS
    Dec 21, 2022 at 0:07
8
\$\begingroup\$

JavaScript (Node.js), 56 bytes

x=>x.replace(/(?<=[aeiou])[^aeiou]/g,x=>x.toUpperCase())

Try it online!

Perl 5 -p, 30 27 26 bytes

s/[aeiou]\K[^aeiou]/\U$&/g

Try it online!

-3 bytes thanks to Sisyphus

-1 byte thanks to Jo King

\$\endgroup\$
1
  • \$\begingroup\$ Wow, another answer! \$\endgroup\$ Dec 17, 2022 at 2:44
7
\$\begingroup\$

Vyxal, 11 bytes

\zp⁽AḊ⁽ǐẆṅḢ

Try it Online!

This is a terrible way to do it but it works.

\zp⁽AḊ⁽ǐẆṅḢ
\zp         # Prepend "z" so that there is a leading consonant
   ⁽AḊ      # Adjacent-group by is-vowel
      ⁽ǐẆ   # Title-case every second item, starting on the first item
         ṅḢ # Join by nothing and remove the leading "z"
\$\endgroup\$
1
  • \$\begingroup\$ Great, it works. Upvoted! 11 bytes might be hard to beat. \$\endgroup\$ Dec 17, 2022 at 2:14
7
\$\begingroup\$

Vyxal, 11 bytes

`° ß`$‡ǐNøṙ

Try it Online!

An alternate 11 byter that uses regex

See this golfing tip of mine that explains why the string "° ß" is "[aeiou] [bcdfghjklmnpqrstvwxyz]"

Explained

`° ß`$‡ǐNøṙ
`° ß`       # The string `[aeiou] [bcdfghjklmnpqrstvwxyz]`
     $      # Make the stack input, ^
      ‡ǐN   # Push a function that title cases a string and then swapscase.
            # This is because regex matches will be vowel-consonant, and title case makes the vowel uppercase, consonant lowercase, swapcase inverts that for the desired result 
         øṙ # Apply that function to regex matches in the input
\$\endgroup\$
1
  • \$\begingroup\$ 11 bytes! Equal best with Steffan! \$\endgroup\$ Dec 17, 2022 at 3:09
6
\$\begingroup\$

R, 48 bytes

\(s)gsub("(?<=[aeiou])([^aeiou])","\\U\\1",s,,T)

Attempt This Online!

\$\endgroup\$
5
\$\begingroup\$

Go, 170 164 bytes

import(."regexp";."strings")
func f(s string)string{return MustCompile(`[aeiou][^aeiou]`).ReplaceAllStringFunc(s,func(x string)string{return x[:1]+ToUpper(x[1:])})}

Attempt This Online!

No (?<=), non-capturing groups only work with Find(All)String(Submatch) which leads to a longer solution, so this mess is what I've had to come with.

  • -6 bytes for simplifying the regex.
\$\endgroup\$
5
\$\begingroup\$

Python 3.8 (pre-release), 78 66 65 bytes

d=0
for c in input():print(end=[c,c.upper()][d>(d:=c in"aeiou")])

Complete program. Thanks to @Neil and @Steffan for making this more concise. Try it online!

Python 3, 73 bytes (@Steffan)

lambda x:re.sub("(?<=[aeiou])[^aeiou]",lambda a:a[0].upper(),x)
import re

Function solution. Try it online!

\$\endgroup\$
7
  • \$\begingroup\$ Great, clever way with python, +1. \$\endgroup\$ Dec 17, 2022 at 2:16
  • \$\begingroup\$ Regex solution is 73 \$\endgroup\$
    – naffetS
    Dec 17, 2022 at 2:23
  • \$\begingroup\$ 66 bytes \$\endgroup\$
    – Neil
    Dec 17, 2022 at 19:12
  • \$\begingroup\$ @chepner Try It Online hasn't been updated in quite a while and isn't currently maintained, so the latest version of Python it has is 3.8 pre-release. A current alternative is Attempt This Online \$\endgroup\$
    – jezza_99
    Dec 17, 2022 at 21:04
  • \$\begingroup\$ Ah, that makes sense. \$\endgroup\$
    – chepner
    Dec 17, 2022 at 21:09
5
\$\begingroup\$

Pip, 21 16 bytes

aRXV.XC;@_.UC_@1

Try It Online!

-5 bytes thanks to @DLosc
Regex solution, ported from @Steffan's regex, with some pip builtin regex patterns used to save bytes

Pip, 21 17 bytes

{Iy>YaNVWUC:aa}Ma

Try It Online!

-4 bytes thanks to @DLosc
Non-regex alternative

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Lookarounds are expensive. Here's a 16-byte regex solution--not as elegant, but much shorter. \$\endgroup\$
    – DLosc
    Dec 19, 2022 at 18:32
  • 1
    \$\begingroup\$ Here's 17 bytes for the non-regex solution (protip: remove the -p flag if you don't need list output). \$\endgroup\$
    – DLosc
    Dec 19, 2022 at 18:36
  • \$\begingroup\$ @DLosc some good tips, cheers \$\endgroup\$
    – jezza_99
    Dec 19, 2022 at 22:06
4
\$\begingroup\$

Ly, 30 bytes

"aeiou"0>ir[sp<l~!' **lf-ol~>]

Try it online!

This isn't even close to the smallest, but the way it works is probably very different from other languages, so I thought it was worth posting.

It uses two stacks, one with a list of vowels, and one with the STDIN string. Each character on the STDIN stack is copied to the vowel stack and the code search to see if there's a match. That "am I a vowel" result is combined with a "was the last char as vowel" result that lives on the stack to decide whether or not to capitalize the current character before printing it.

"aeiou"                        - push "is a vowel" comparison data on stack
       0                       - push "0" as "was last char a vowel" starter val
        >i                     - switch to new stack, read STDIN onto it
          r                    - reverse stack
           [                 ] - for each input char/codepoint
            sp<l               - stash the char, delete, switch stacks and restore
                ~!             - search for the char in "aeiou", negate result
                  '            - push " " (32), the "capitalize" codepoint offset
                    *          - multiple to clear if not this IS a vowel
                     *         - multiple against "was previous char vowel?" result 
                      l        - reload the current char/codepoint
                       f-      - flip stack and subtract to capitalize if needed
                         o     - output current char
                          l~   - reload char, search against vowels
                            >  - switch back to the STDIN stack
\$\endgroup\$
4
\$\begingroup\$

Vim, 23 keystrokes

:s/[aeiou]\+\zs./\u&/g<cr>

:s/                        # Search and replace...
   [aeiou]\+               #    A string of one or more vowels
            \zs            #    (start the match here)
               .           #    Any character
                           #    (because of greedy matching, this will always be the first consonant)
                /          # Replace with
                 \u        #    Make uppercase
                   &       #    The matched string (after \zs)
                    /g<cr> # Replace all occurrences
\$\endgroup\$
4
\$\begingroup\$

Retina 0.8.2, 25 bytes

T`aeioul`aeiouL`[aeiou]+.

Try it online! Explanation: Transliterates vowels to themselves and other lowercase letters to uppercase letters, but only the letter after a run of vowels. (This is so that a double vowel doesn't confuse the transliteration.)

Alternative, also 25 bytes:

rT`aeioul`aeiouL`[aeiou].

Try it online! Explanation: The r makes it match the pattern from right to left solving the double vowel problem.

Both programs work in Retina 1 but 8 bytes can be saved because the aeiou can be replaced by v in the transliteration patterns.

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

Dart (v2.18.4), 149 80 bytes

f(s,[d=0])=>String.fromCharCodes([for(s in s.runes)s^d&~(d=68174912>>s%32)&32]);

Extra test-cases:

Input Output
loremipsumdolorsitamet loReMiPsuMdoLoRsiTaMeT
namauctoranteelementumarculaciniaaceuismodestiaculis naMauCtoRaNteeLeMeNtuMaRcuLaCiNiaaCeuiSmoDeStiaCuLiS

Thanks to @steffan who cut down to 80 bytes (!) by porting @arnauld answer.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ I got this down to 104 bytes: f(s,[v,i=0])=>s.split('').map((e)=>i++<1||!(v='aeiou'.contains)(s[i-2])||v(e)?e:e.toUpperCase()).join(); \$\endgroup\$
    – naffetS
    Dec 18, 2022 at 0:05
  • 1
    \$\begingroup\$ Or 89 by porting AlephSquirrel's answer: f(s,[d=0])=>s.split('').map((e)=>d>(d='aeiou'.contains(e)?1:0)?e.toUpperCase():e).join(); \$\endgroup\$
    – naffetS
    Dec 18, 2022 at 0:07
  • 1
    \$\begingroup\$ Or 80 by porting Arnauld's answer: f(s,[d=0])=>String.fromCharCodes([for(s in s.runes)s^d&~(d=68174912>>s%32)&32]); \$\endgroup\$
    – naffetS
    Dec 18, 2022 at 0:12
4
\$\begingroup\$

Japt, 13 bytes

r"%v%c"ÈÎ+XÌu

Try it

r"%v%c"ÈÎ+XÌu     :Implicit input of string
r                 :Replace
 "%v%c"           :RegEx /[aeiou][b-df-hj-np-tv-z]/gi
       È          :Pass each match through the following function as X
        Î         :  First character
         +        :  Append
          XÌ      :  Last character
            u     :  Uppercased
\$\endgroup\$
3
\$\begingroup\$

C (clang), 48 bytes

d;f(*s){for(d=1;*s;)*s++^=d-(d='Xz'%*s>0)&32;}

Try it online!

dingledooper's answer as a function.

\$\endgroup\$
3
\$\begingroup\$

Charcoal, 22 bytes

⭆θ⎇№⌕A⭆θ№aeiouλ10⊖κ↥ιι

Try it online! Link is to verbose version of code. Explanation: Maps each letter to its vowel-ness as a binary flag, then searches for the substring 10 in the result, the second character of which is where the consonants that needs to be uppercased are.

 θ                      Input string
⭆                       Map over letters and join
   №                    Count of
                  κ     Current index
                 ⊖      Decremented
       θ                In input string
      ⭆                 Map over letters and join
        №               Count of
              λ         Inner letter in
         aeiou          Literal string `aeiou`
    ⌕A                  Find all matches of
               10       Literal string `10`
  ⎇                     If found then
                    ι   Current consonant
                   ↥    Uppercased
                     ι  Else current letter
                        Implicitly print
\$\endgroup\$
3
\$\begingroup\$

sed, 25 bytes

s/[aeiou][^aeiou]/\U\l&/g

Attempt This Online!

It makes the whole match uppercase and then it turns first letter to lowercase. This is 5 bytes shorter than s/([aeiou])([^aeiou])/\1\u\2/g solution and it also doesn't require -E flag.

\$\endgroup\$
3
\$\begingroup\$

05AB1E, 17 bytes

'zì.γžMså}2Å€™}J¦

Try it online!

  • -4 thanks to Kevin Cruijssen

Port of Steffan's Vyxal answer

'zì.γžMså}2Å€™}J¦         # Implicit input                           TOP OF THE STACK:
'zì                       # Prepend a 'z'                            "zhelloworldandhellocodegolf"
   .γ    }                # Group by
     žM                   #  The string of vowels                    'aeiou'
       så                 #  Contains the letter                     ["zh", "e", "ll", "o", "w", "o", "rld", "a", "ndh", "e", "ll", "o", "c", "o", "d", "e", "g", "o", "lf"]
          2Å€ }           # Every second item:
             ™            #  Convert to title case                   ["Zh", "e", "Ll", "o", "W", "o", "Rld", "a", "Ndh", "e", "Ll", "o", "C", "o", "D", "e", "G", "o", "Lf"]
               J          # Join everything                          'ZheLloWoRldaNdheLloCoDeGoLf'
                ¦         # And remove the leading 'z'               'heLloWoRldaNdheLloCoDeGoLf'
\$\endgroup\$
2
  • \$\begingroup\$ š can be ì so the input will remain a string. Then you can change to å and remove the first J for -2. In addition, 05AB1E has an every b'th builtin (Å€), so ā<ÈÅÏ™} can be 2Å€™} for another -2. 17 bytes \$\endgroup\$ Dec 27, 2022 at 10:48
  • \$\begingroup\$ @KevinCruijssen thanks \$\endgroup\$
    – The Thonnu
    Dec 27, 2022 at 17:08
2
\$\begingroup\$

Retina, 23 bytes

(?<=[aeiou])[^aeiou]
$u

Try it online!

$u is replace with uppercase.

\$\endgroup\$
2
\$\begingroup\$

Jelly, 12 bytes

Œue€ØḄ<ƝŻTƲ¦

A monadic Link that accepts a list of lowercase characters and yields a list of characters.

Try it online!

How?

Œue€ØḄ<ƝŻTƲ¦ - Link: list of lowercase characters, S
           ¦ - sparse application (to S)...
          Ʋ  - ...to indices: last four links as a monad - f(S):
    ØḄ       -     lowercase consonants
   €         -       for each (character in S):
  e          -         exists in? -> 1 if a consonant else 0
       Ɲ     -     for neighbours:
      <      -       less than? -> 1 if [0,1] else 0
        Ż    -     prepend a zero
         T   -     truthy indices -> indices of consonants directly after a vowel
Œu           - ...action: convert to uppercase
\$\endgroup\$
2
\$\begingroup\$

Factor, 51 bytes

[ R/ [aeiou][^aeiou]/ [ "\0 "v- ] re-replace-with ]

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Zsh --extendedglob, 52 bytes

<<<${1//(#m)[aeiou][^aeiou]/$MATCH[1]${(U)MATCH[2]}}

Try it Online!   69 bytes

Hat-tips: one two

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

Python 3, 90 bytes

lambda x:"".join(b.upper()if a in"aeiou"and b not in"aeiou"else b for a,b in zip(" "+x,x))

Would be 71 bytes if didn't have to deal with repetitive vowels, still got 90 bytes though. Try it online!

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

Raku, 26 bytes

{S:g[<[aeiou]>+<(.]=$/.uc}

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ How does this work? Could you write an explanation please? \$\endgroup\$
    – south
    Dec 24, 2022 at 1:29
  • \$\begingroup\$ @south It substitutes (S) each occurrence (globally, :g) in the input string of one or more vowels (<[aeiou]>+) followed by any character (.) by the matched text ($/) converted to uppercase (.uc). Or rather it would do that if not for the capture marker (<() which causes the matched text to include only the single character following the vowels, so that's the only character that gets replaced with its uppercase version. The opening capture marker <( can be paired with a closing marker )>, but it's unnecessary here since the matched text extends to the end of the string. \$\endgroup\$
    – Sean
    Dec 26, 2022 at 19:54
1
\$\begingroup\$

Ruby -p, 36 bytes

gsub /(?<=[aeiou])[^aeiou]/,&:upcase

Attempt This Online!

\$\endgroup\$
0
\$\begingroup\$

Pyth, 19 bytes

sm?*Z!=Z}d"aeiou"r1

Try it online!

Explanation

sm?*Z!=Z}d"aeiou"r1ddQ    # implicitly add ddQ to the end
                          # implicitly assign Q = eval(input())
s                         # sum of
 m                   Q    # map lambda d over Q
  ?                       # ternary if (
   *Z!                    # Z and not
      =Z}d"aeiou"         # assign Z to d being a vowel):
                 r1d      #   d capitalized
                    d     # else: d
\$\endgroup\$
0
\$\begingroup\$

Ruby 2.7, 110 bytes

->(s){v="aeiou";s.chars.map.with_index{v.include?(s[_2-1])&&!v.include?(_1)?(_1.upcase):_1}.join}
\$\endgroup\$

Your Answer

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

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