21
\$\begingroup\$

I don't like strings with more than three vowels in a row. Can you write a program that removes all the vowels I don't want from words?

You may write a program or function, taking input via STDIN (or closest alternative), command-line argument or function argument and outputting the result via STDOUT (or closest alternative), function return value or function (out) parameter.

Input is a string containing only printable ASCII character (0x20 to 0x7E, inclusive).

Output is a string containing only runs of at most 3 consecutive vowels. If there is a run of more than 3 consecutive vowels in the input string, your program should produce an output string including the first three vowels encountered in that run, discarding any further consecutive vowels.

Y is not a vowel for the purposes of this challenge.

This is code golf, so the shortest code (in bytes) wins.

Test Cases

"Aeiou" => "Aei"
"screeeen" => "screeen"
"We're queueing up for the Hawaiian movie." => "We're queung up for the Hawaiin movie."
"Spaces break runs: aei iou." => "Spaces break runs: aei iou."
\$\endgroup\$
1
  • 2
    \$\begingroup\$ You should include some more tests with mixed cases, like aaYYAAaaaAERGH. \$\endgroup\$
    – Zgarb
    Commented Dec 11, 2015 at 1:20

24 Answers 24

11
\$\begingroup\$

Unreadable, 1647 bytes

'"""""'""'""""""'"""'""""""'""'""'"""'""""""""""'"""""""""'"""""""""'""""""'"""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'"""""""'"""'"""""""""'""""""'"""'""""""""'""""""""'""""""""'""""""""'"""""""'"""'"""""""""'""""""'"""'""""""""'""""""""'""""""""'""""""""'"""""""'"""'"""""""""'""""""'"""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'"""""""'"""'"""""""""'""""""'"""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'"""""""'"""'"""""""""'""""""'"""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'"""""""'"""'"""""""""'""""""'"""'""""""""'""""""""'""""""""'""""""""'"""""""'"""'"""""""""'""""""'"""'""""""""'""""""""'""""""""'""""""""'"""""""'"""'"""""""""'""""""'"""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'"""""""'"""'"""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'""""""""'"""""""'"""'""""""""'"""'"""'"""'"""'"""'"""'"""'"""'"""'"""'"""'"""""""""'""'""'""'""'""""""'""'"""'""""""""'"""""""'""'"""'"'"""""""'""'""'"""'""""""'""'"""'""'"""""""'""'"""'""""'"'"""""""'""'""'"""'""""""'""'"""'""""""""'"""

Explanation

This program is equivalent to pseudocode like this:

while (cp = (ch = read)) + 1 {
    (
        (cp -= 65) ?    // A
            (cp -= 4) ?     // E
                (cp -= 4) ?     // I
                    (cp -= 6) ?     // O
                        (cp -= 6) ?     // U
                            (cp -= 12) ?    // a
                                (cp -= 4) ?     // e
                                    (cp -= 4) ?     // i
                                        (cp -= 6) ?     // o
                                            (cp - 6) ?      // u
                                                0
                                            : 1
                                        : 1
                                    : 1
                                : 1
                            : 1
                        : 1
                    : 1
                : 1
            : 1
        : 1
    ) ? ((--vs)+4) ? print(ch) : (++vs) : {
        print(ch)
        vs = 0
    }
}

with the following variable assignments:

0   (unused)   (13 bytes)
1   cp         ( 4 bytes; occurs 20× in the code)
2   vs         ( 7 bytes; occurs  5× in the code)
3   ch         (10 bytes; occurs  3× in the code)

As you can see, I avoided variable slot 0 because 0 is such a long constant to write.

So we read each character and store the value in both cp and ch. We will modify cp but keep ch around so that we can print it if necessary. We successively subtract numbers 65, 4, 4, 6, etc. from cp to check if it’s each of the 10 possible vowel characters in ASCII (note the very last one doesn’t need to be an assignment).

vs always contains 3 less than the number of vowels still allowed to be printed. It starts out at 0, so 3 vowels can be printed. When it reaches -3, we stop printing vowels.

If we encounter a non-vowel (including the space), we execute print(ch) followed by vs = 0. As you have probably guessed, this resets the vowels counter.

If we encounter a vowel, we execute ((--vs)+4) ? print(ch) : (++vs). Let’s break this down:

  • decrement vs;
  • if the value is now -4, we’ve gone too far, so don’t print anything, but increment vs back to -3 so we will continue to refuse to print vowels;
  • otherwise, print the character.
\$\endgroup\$
2
  • 1
    \$\begingroup\$ This language is true to its name. \$\endgroup\$
    – jqkul
    Commented Dec 11, 2015 at 7:46
  • 2
    \$\begingroup\$ I always wonder in these languages... "Did they actually write this out by hand? If so, I pity them..." +1 \$\endgroup\$ Commented Dec 11, 2015 at 12:43
10
\$\begingroup\$

Retina, 25 bytes

i`([aeiou]{3})[aeiou]+
$1

Try it online.

Fairly straightforward regex substitution. This also works for the same byte count:

Ri`(?<=[aeiou]{3})[aeiou]
\$\endgroup\$
1
  • 5
    \$\begingroup\$ Finally! An online interpreter! You should consider linking to it on your github page. \$\endgroup\$
    – mbomb007
    Commented Dec 11, 2015 at 17:21
8
\$\begingroup\$

JavaScript (ES6), 42

As an anonymous function

s=>s.replace(/[aeiou]+/gi,v=>v.slice(0,3))
\$\endgroup\$
6
\$\begingroup\$

Pyth, 21 bytes

sfg3=Z&}rT0"aeiou"hZz

Try it online: Demonstration or Test Suite

Explanation:

I iterate through all chars and keep track of how many vowels I passed using a counter. Every time I pass a char, which is not a vowel, I reset the counter to 0. I reomve chars, whenever the counter is > 4.

sfg3=Z&}rT0"aeiou"hZz   implicit: z = input string
                                  Z = 0
 f                  z   test every char T in z; keep chars, that return true:
        rT0                convert T to lower
       }   "aeiou"         test if T is a vowel
      &           hZ       logical and with Z+1, 
                           gives 0 if ^ is false, otherwise Z+1
    =Z                     update Z with this value
  g3                       test if 3 >= Z
s                       sum up all remaining chars and print
\$\endgroup\$
5
\$\begingroup\$

Perl, 27 characters

(26 characters code + 1 character command line option)

s/[aeiou]{3}\K[aeiou]+//gi

Not a big deal, just a rare occasion I remember \K exists.

Sample run:

bash-4.3$ perl -pe 's/[aeiou]{3}\K[aeiou]+//gi' <<< "
> Aeiou
> screeeen
> We're queueing up for the Hawaiian movie.
> Spaces break runs: aei iou."

Aei
screeen
We're queung up for the Hawaiin movie.
Spaces break runs: aei iou.
\$\endgroup\$
3
  • 2
    \$\begingroup\$ When I wrote up the Retina answer I thought "I wish .NET regex had \K". :) \$\endgroup\$ Commented Dec 10, 2015 at 15:15
  • \$\begingroup\$ Interesting, @MartinBüttner. I had the feeling those regular expressions were put on serious steroid diet. For curiosity, do they have recursive subpattern? Can help to spare one vowel enumeration, though the result is longer: s/([aeiou]{1,3})(?1)+/$1/gi. \$\endgroup\$
    – manatwork
    Commented Dec 10, 2015 at 15:49
  • \$\begingroup\$ Unfortunately, they don't have pattern reuse either. Those are the two things that occasionally make me switch to Perl or PCRE. When I get around to patching some simple things into Retina's regex flavour, I think I'll add those (not true recursion, but at least pattern reuse and finite recursion). \$\endgroup\$ Commented Dec 10, 2015 at 15:54
3
\$\begingroup\$

APL, 40 chars

{⍵/⍨1↓4≠⊃+/(1-⍳4)⌽¨⊂'aeiouAEIOU'∊⍨' ',⍵}

In English:

  • 'aeiouAEIOU'∊⍨' ',⍵: find the vowels (and prepend a space to break on rotation);
  • (1-⍳4)⌽¨⊂: rotate 0, 1, 2, 3 times (with wrap-around) pushing to the right the boolean vector;
  • ⊃+/ sum: the rotations and unbox
  • 1↓4≠: find the different than 4, and remove the first one (to cather for the space we prepended)
  • ⍵/⍨: in the argument, keep only the element where the sum was different than 4.
\$\endgroup\$
2
\$\begingroup\$

C, 166 bytes

not the shortest answer by far but nicely golfed I think..

#define V v[1][i]!=
#define P printf("%c",v[1][i]),j
j;main(i,v)char**v;{for(i=0;V 0;i++)(V 97&V 'e'&V 'i'&V 'o'&V 'u'&V 65&V 69&V 73&V 79&V 85)?P=0:j>3?j++:P++;}

test case:

$ a.exe "We're queueing up for the Hawaiian movie."

We're queung up for the Hawaiin movie.

$ wc -c vowels.c 

166 vowels.c
\$\endgroup\$
2
\$\begingroup\$

Javascript ES6, 43 chars

s=>s.replace(/([aeiou]{3})[aeiou]*/gi,"$1")

Test:

f=s=>s.replace(/([aeiou]{3})[aeiou]*/gi,"$1")
;`"Aeiou" => "Aei"
"screeeen" => "screeen"
"We're queueing up for the Hawaiian movie." => "We're queung up for the Hawaiin movie."
"Spaces break runs: aei iou." => "Spaces break runs: aei iou."`
.replace(/"/g,"").split("\n").every(s=>f((s=s.split(" => "))[0])==s[1])
\$\endgroup\$
2
\$\begingroup\$

Mathematica, 68 bytes

a=Characters@"aeiouAEIOU";StringReplace[#,b:a~Repeated~{3}~~a..:>b]&

The regex answer would be the same length, but who uses regex?

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

Java, 115 bytes

class a{public static void main(String[] a){System.out.println(a[0].replaceAll("(?i)([aeiou]{3})[aeiou]*","$1"));}}

Expects input as program parameter.

Unit test output:

Aei
screeen
We're queung up for the Hawaiin movie.
\$\endgroup\$
2
  • \$\begingroup\$ Save one byte by removing the space between String[] and a. String[]a \$\endgroup\$
    – Poke
    Commented Jun 27, 2016 at 19:23
  • \$\begingroup\$ Save 2 bytes by using print rather than println. I don't believe the spec requires a trailing newline. \$\endgroup\$
    – Poke
    Commented Jun 27, 2016 at 19:26
2
\$\begingroup\$

Arturo, 44 bytes

$=>[replace&{/(?i)([aeiou]{3})[aeiou]+}"$1"]

Try it

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

Vyxal s, 60 bits1, 7.5 bytes

⁽AḊƛAa[3Ẏ

Try it Online!

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

Tcl, 82 56 bytes

Saved 26 bytes thanks to the comment of @naffetS


Golfed version. Try it online!

proc f s {regsub -all {(?i)([aeiou]{3})[aeiou]*} $s \\1}

Ungolfed version. Try it online!

proc remove_vowels {s} {
    regsub -all -- {([aeiouAEIOU]{1,3})[aeiouAEIOU]*} $s {\1} result
    return $result
}

puts [remove_vowels "Aeiou"]  
puts [remove_vowels "screeeen"]
puts [remove_vowels "We're queueing up for the Hawaiian movie."]
puts [remove_vowels "Spaces break runs: aei iou."]


# "Aeiou" => "Aei"
# "screeeen" => "screeen"
# "We're queueing up for the Hawaiian movie." => "We're queung up for the Hawaiin movie."
# "Spaces break runs: aei iou." => "Spaces break runs: aei iou."
\$\endgroup\$
1
2
\$\begingroup\$

Japt, 9 bytes

r"%v+"ȯ3

Try it

r"%v+"ȯ3     :Implicit input of string
r             :Replace
 "%v+"        :RegEx /[aeiou]+/gi
      È       :Pass each match through the following function
       ¯3     :  Slice to length 3
\$\endgroup\$
2
\$\begingroup\$

Thunno 2 , 24 bytes

Oı"([%]+)"kWDL+%ḄıDhṃ?3ɱ

Attempt This Online!

Feel like maybe I'm doing something wrong

Explained

Oı"([%]+)"kWDL+%ḄıDhṃ?3ɱ
O                        # Split the input on spaces
 ı                       # to each item in that:
  "([%]+)"kWDL+%Ḅ        #   split on the regex ([AEIOUaeiou]+) - the () makes it so that the group is retained   
                 ı       #   to each group:
                  Dhṃ?   #     if it starts with a vowel:
                      3ɱ #       keep only the first three items
# Ṡ flag joins on spaces before printing
\$\endgroup\$
1
  • \$\begingroup\$ In 2.2.0, 11 bytes with J flag: µñṃıDJṃh?3ɱ \$\endgroup\$
    – The Thonnu
    Commented May 14, 2023 at 14:44
1
\$\begingroup\$

Perl 6,  36  35 bytes

{S:g:i/(<[aeiou]>**3)<[aeiou]>+/$0/} # 36 bytes

$ perl6 -pe 's:g:i/(<[aeiou]>**3)<[aeiou]>+/$0/' # 34 + 1 = 35 bytes

usage:

$ perl6 -pe 's:g:i/(<[aeiou]>**3)<[aeiou]>+/$0/' <<< "
> Aeiou
> screeeen
> We're queueing up for the Hawaiian movie.
> Spaces break runs: aei iou."
Aei
screeen
We're queung up for the Hawaiin movie.
Spaces break runs: aei iou.
\$\endgroup\$
1
\$\begingroup\$

C (205 bytes)

#include <stdio.h>
#define T(x)for(i=0;i<10;++i){if(v[i]==x){b=x;m=1;break;}}putchar(c);
main(b,c,i,m){char v[]="aeiouAEIOU";
while((c=getchar())!=EOF){if(!m){T(c);}else{if(b==c)continue;else{m=0;T(c);}}}}

(One line break added for clarity)

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

Scala, 107 bytes

readLine.foldLeft("",0)((a,n)=>if(!"aeiou".contains(n|32))a._1+n->0 else if(a._2>2)a else(a._1+n,a._2+1))_1
\$\endgroup\$
1
\$\begingroup\$

Seriously, 34 bytes

,;ù0╗`Ok"aeiou"Okd-Y;╜+*;╗4>`M@░εj

Hex Dump:

2c3b9730bb604f6b226165696f75224f6b
642d593bbd2b2a3bbb343e604d40b0ee6a

Try it online

It uses the same algorithm as the Pyth answer, mapping over the string while keeping track of the length of the current run of vowels in a register, incrementing it whenever the current character is a vowel, and checking whether it has exceeded the allowed length, returning 0 if so, and then filtering the original string with this generated filter. It will be a lot shorter once we can use set subtraction on strings. (The Ok can be deleted and the Okd can be replaced with just @). I hear this feature is coming in the next update....

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

x86 MS-DOS .COM file, 44 bytes 36 bytes

.COM files are widely supported from MS-DOS 1 through the present---I'm running in dosemu, using 8086 commands only.

Reduced from 44 to 36 bytes by using REPNE SCASB to test for vowels instead of using a separate command to test each vowel.

Hex dump, reversible using `xxd -r -seek -256`:
0100: b3 03 43 b4 08 cd 21 88 c2 24 df b1 05 bf 1f 01   ..C...!..$......
0110: f2 ae 74 02 b3 05 4b 74 e9 b4 02 cd 21 eb e4 41   ..t...Kt....!..A
0120: 45 49 4f 55                                       EIOU

Unassembled using debug:
0100 B303    MOV BL,03     ; initialize counter to 3 (will increment by 1 to be 4)
0102 43      INC BX        ; increment counter--runs each time it hits 0 so it never goes <0
0103 B408    MOV AH,08     ; 
0105 CD21    INT 21        ; with AH=8, read 1 char without echo
0107 88C2    MOV DL,AL     ; copy input for potential output
0109 24DF    AND AL,DF     ; make input uppercase for testing
010B B105    MOV CL,05     ; count of 5 vowels to test against
010D BF1F01  MOV DI,011F   ; location of first vowel to test against
0110 F2AE    REPNE SCASB   ; test input against each vowel
0112 7402    JZ 0116       ; if input was not a vowel:
0114 B305    MOV BL,05     ;    reset counter to 5 (will decrement by 1 to be 4)
0116 4B      DEC BX        ; decrement counter regardless
0117 74E9    JZ 0102       ; if hit 0 (fourth or later vowel): goto 102
0119 B402    MOV AH,02     ; 
011B CD21    INT 21        ; with AH=2, print char
011D EBE4    JMP 0103      ; go to 103 for next character

bytes 011f-0123 contain the uppercase vowels AEIOU
\$\endgroup\$
1
\$\begingroup\$

Matlab / Octave, 54 bytes

@(s)regexprep(s,'(?<=[aeiouAEIOU]{3})[aeiouAEIOU]','')

Example:

>> @(s)regexprep(s,'(?<=[aeiouAEIOU]{3})[aeiouAEIOU]','')
ans = 
    @(s)regexprep(s,'(?<=[aeiouAEIOU]{3})[aeiouAEIOU]','')

>> ans('We''re queueing up for the Hawaiian movie.')
ans =
We're queung up for the Hawaiin movie.

Try it at ideone.

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

V, 21 bytes (noncompeting)

ñ[aeiou]ñÍãqû3}úsq*

Try it online!

Explanation:

ñ[aeiou]ñ                     "Assign the string `[aeiou]` to register 'q'
         Íã                   "Search and replace on multiple lines (case insensitive):
           <C-r>q             "Register 'q'
                 û3}          "Repeated 3 times
                    ús        "Mark the following to be removed:
                      <C-r>q* "Register 'q' repeated any number of times

This is just barely shorter than the more straightforward solution:

Íã[aeiou]û3}ús[aeiou]*

(22 bytes)

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

Jelly, 12 11 bytes

ḟ€ØckŻḣ€4FḊ

Try it online!

Copy-paste from my answer to a similar challenge, except somehow even worse. e€Øc‘×¥\<4x@ is nicer for one more byte (check edit history for an explanation).

 €             For each character of the input,
ḟ              filter out
  Øc           vowels.
     Ż         Prepend a 0 to the input, and
    k          partition that after truthy (nonempty) positions in the original.
      ḣ€4      Keep the first 4 elements of each slice,
         F     flatten the slices,
          Ḋ    and remove the 0.
\$\endgroup\$
0
\$\begingroup\$

Ruby, 44 bytes

><<$<.read.gsub(/([aeiou]{3})[aeiou]+/i,'\1')

Example:

% ruby -e "$><<$<.read.gsub(/([aeiou]{3})[aeiou]+/i,'\1')" <<< "
Aeiou
screeeen
We're queueing up for the Hawaiian movie.
Spaces break runs: aei iou."

Aei
screeen
We're queung up for the Hawaiin movie.
Spaces break runs: aei iou.
\$\endgroup\$
2
  • \$\begingroup\$ You wrote it: “Input is a string containing only printable ASCII character (0x20 to 0x7E, inclusive).” Then why spending extra characters with $<.read to make it handle multiline input (thus containing out of range character 0x0a) instead of gets? \$\endgroup\$
    – manatwork
    Commented Dec 15, 2015 at 16:24
  • \$\begingroup\$ @manatwork that's a really good point, thank you! Think it might save 2-3 bytes :) \$\endgroup\$ Commented Dec 15, 2015 at 16:38

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