How To Remove Vowels From a String in JavaScript

Algorithms interview prep

Matt Cummings
Jan 14 · 13 min read
Photo by Moritz Schmidt on Unsplash

Recently, I was taking notes and trying to come up with an example of a function that would be used in a library that specialized in string manipulation.

I wrote myself a couple of examples, when an idea popped into my head: “Wouldn’t it be good practice to try and create a function that takes a string, and gives it back without vowels?”

That’s how I started coding this algorithm, which I decided to call vowelCut.

I just came back from the holiday break, so a light problem like this was a great way to get myself back into the groove of coding algorithms. Giving yourself small challenges like these puts you in a certain mindset, a mental pool if you will, one that I certainly hadn’t dipped my feet into for a while.

It’s also been a while since I messed around with a handful of things in Vanilla JS or with regular expressions, both of which are particularly useful when it comes to string manipulation.

You can follow along with everything in this article via this GitHub repo I’ve created: vowelCut.

The first two files of this cover the creation of this algorithm and come in annotated and plain versions, so use whichever one works best for you. I’ll be posting the code from the plain version, as the comments largely reflect what I’m writing in this article.

(Note: The main portion of this article treats Y as a vowel in all instances. There’s another optional file in the repo that’s concerned with considering Y as a vowel given certain criteria. This optional file adds some complexity to our algorithm. It corresponds with the optional part of this article.)

With all that out of the way, let’s start going over the construction process!


Considering Specific Endpoints

Writing out your endpoints before writing the algorithm can help establish what you want it to do.

The above is a brief bulletin of what I wanted to accomplish with this function.

By writing down endpoints, we give ourselves something concrete to refer to when it comes to making the algorithm. This also helps us keep in mind what constraints we might have or potential difficulties that might arise.

Accepting valid strings

The first three endpoints deal with analysis of the argument given. A string should have certain qualities, and if it does not, an error message should be returned to the user in regards to what the issue is and the remedy for it.

First, since the whole goal of this algorithm is string manipulation, we better make sure what we’re actually working with is a string in the first place! That’s easily solved with the typeof operator (discussed later on), but doesn’t account for strings that are undesirable.

I really wanted to be strict about the kinds of strings this algorithm was going to process — after all, if there are no letters in it, why bother looking for vowels in the first place? That’s where the need to identify strings that lacked alphabetical characters arose.

Finally, I wanted a specific message if an empty string somehow made it through.

While our second endpoint already accounts for a lack of letters, a string having no content at all is markedly different. Ergo, we should have a message reflecting this situation as well.

Avoiding unnecessary processing of vowel-less strings

We want to ensure that we return a string with the vowels removed — in the case of a one-character string that is only a vowel, that means we should just return an empty string.

If we have a one-character string that isn’t a vowel, we should just return the character.

Providing a clear example of algorithm functionality

Lastly, we should have an example sentence and what its vowel-removed resultant would be.

I’m a fan of Princess Peach (Super Smash Bros. Melee, anyone?), and I wanted a fairly long sentence to work with so that worked out nicely for me. By knowing what we are going to provide and receive, we can use this sentence again later and compare it.

Notice how all of these are really simple endpoints. If you’re not comfortable with unit testing, an exercise like this is a great place to start.

The simplicity of this algorithm and its helper functions leads to easy debugging so you can focus on your unit test composition without going crazy over the associated code.

I’m not covering unit tests in this article, but perhaps I will write one in the future pertaining to that, probably using this as an example.


Algorithm Composition

With all of our endpoints established, we can get on with writing the actual code!

Remember that algorithms tend to have a lot going on with them, and rather than keep all that code in one space, it’s best to compartmentalize it into various helper functions we can call as needed.

I’m only using two helpers in this example due its low level of complexity, but it’s still much more organized and readable to utilize them in any case.

Accounting for invalid strings

The first three endpoints all dealt with how to treat the strings we receive as arguments (if they’re even strings, that is).

This is the first thing we want our algorithm to see — if we’ve got an argument that’s not going to work, we shouldn’t even start to process it. Rather, we should terminate the function early. In our case, that means throwing a return whose value is an error message.

First, we’ll save the error messages as variables.

const notAStringMessage = "Not a string. Please provide an argument that is a string."const noLetterString = "Please write a string that has letters in it."const zeroLengthStringMessage = "Please write a string 1 or more characters long."

Then we build our first helper method, isAValidString(string). It will first assess whether the argument is received via the typeof operator.

Remember, this operator will assess the data type of something immediately after it, and the return value of this assessment is a lowercase string (i.e. if the datatype is a number, it will return “number”, a string will return “string”).

If the argument is not a string, we return the error message reflecting that.

if(typeof string!== "string"){return notAStringMessage}

If the argument is a string, we can now determine the quality of those strings.

First, we’ll check if the string is actually populated by assessing its length. An empty string has a length of zero, and if this rings true, we should return the appropriate error message.

if (string.length === 0){return zeroLengthStringMessage}

If the string isn’t empty, we can move on to our final assessment, which uses a simple regex to check whether letter elements are in the string.

The regex used is /[a-zA-Z]/, a character class that can be used to check a string for all letters in the alphabet, regardless of their case.

(Alternatively, we could also use the case-insensitive flag like so: /[a-z]/i. It’s something minor, but offers a different approach to readability. It’s purely the preference of you and the others that read your code.)

If the string contains no letters, there’s obviously no point in checking it for vowels, and we should return an error message to the user reflecting that.

if(/[a-zA-Z]/.test(string) === false){return noLetterString}

If all the above conditionals have returned false, that means we have a valid string! We can return true as the last line of this function’s code and close it.

Checking a string for vowels

Now that we’ve ascertained that the input is a valid string, we can see whether or not it has vowels. This calls for our second helper function, aptly named hasVowels.

The first thing we’ll do is make everything lowercase. This is so I can compare a regex to see if the word has any vowels.

(Side note: I just realized while reviewing this code, I could’ve again used the trusty i flag to make my regex case insensitive, eliminating the need to lowercase everything. Alas, the code works fine this way too!)

The .test method will compare a string to a regex and return a boolean if that string contains the regex. The character class I used looks for any vowels within the string it’s comparing, and will thus return true or false based on that.

This is used in vowelCut to save on processing time — per the rules established in the previous function, a string like MDM is valid, but there’s no need to go through the vowel-cutting process if there are no vowels to cut in the first place!

Therefore, when this function is called on the string, vowelCut receives an argument and returns false, we just give back the original string. Only when it’s true do we actually start string manipulation.

Cutting the vowels

At this point, we have established that the argument vowelCut has received a valid string, and a string that has vowels at that. We can finally begin the vowel-cutting process!

let characterArray = string.split("")
return characterArray.map(character => {
if(/[aeiouyAEIOUY]/.test(character)){
character = ""
} else {return character}
}).join("")

The easiest way I found to do this was to split the string into individual characters via the split method, with an empty string as the delimiter. This means every character in the string is converted into its own element in a new array. For example: “Well hi!” becomes [“W”,”e”,”l”,”l”,” “,”h”,”i”,”!”] .

Since we have an array, we can now iterate through it. The iterative function I chose to use is map, because it creates a new array. We’ll convert this new array back to a string in a little bit.

The callback function I’m giving map checks to see if that character is a vowel, and if it is, replaces that vowel with an empty string. If the character isn’t a vowel, we just return the character as-is.

When map has finished, we get a new array that shouldn’t contain any vowels. From there, we can convert it to a string with join, using a space as a delimiter to keep the newly-transformed words separated.


Completed Algorithm Overlook

Before we wrap this up, let’s take a quick look at the final composition of this algorithm.

By referencing the code above, we can briefly review how this algorithm processes data and the order of this process.

  1. Check to see if string is valid, end function early by returning an appropriate error message.
  2. Check valid strings for vowels. If no vowels exist, end function early by returning the same string that was provided.
  3. If a string has vowels, return an empty string if the string is a single character. For strings of any other length, cut the vowels out systematically. Return the altered string.

And that’s that! We have created a function that removes vowels from any string we have deemed valid.

If you want to stop here, that’s great. If you want to see how to modify this algorithm to make it a little more complex, please continue reading below!


Optional: Accounting for Y as a Vowel

Note: Please refer to the vowel-algorithm-Y-consideration.js file if you’re using the GitHub repo to follow along. There are obviously new functions that are composed, but also be aware of the alteration to the established functions.

A way to make this algorithm a little more complex is to account for the paradoxical nature of Y. In English, Y is needed to function as both a vowel and a consonant at times.

Recognizing and building functionality around constraints

The rules for when Y is a vowel or not seem comprehendible enough at first glance:

Taken from Merriam-Webster, we can see the criteria for Y as a vowel depends on the number of other vowels in the word, as well as Y’s placement within that word.

The problem with these rules from a programming aspect is that syllables are not an easily-defined thing. You can’t do something like break a word into thirds or fourths and expect to get actual syllables each time.

There is the possibility of utilizing an API for syllable recognition, but that’s a little beyond the scope of what we’re trying to do here.

Even if we did have that, we’d then have to account for the fact that this algorithm currently takes strings that may or may not contain actual words. To account for that, we’d probably have to utilize some sort of dictionary API. You see where I’m going with this?

So, let’s try and disregard syllable criteria when it comes to Y as a vowel. The logic we’re left with is basically this: “Y is a vowel when it is the only vowel in a word, or is at the end of a word.”

Let’s also count Y as vowel when it’s the only thing present in a string to make our lives easy.

That’s a lot easier to work with now! Let’s make a new function, YIsAVowel that follows this logic.

Creating a function to recognize Y as a vowel

The first thing we’ll do is lowercase the string for ease of checking it out. Then, we shall check if the last index of the string ends in Y. If it does, Y is a vowel, so we’ll return true. Using the charAt method here to check the string also accounts for the string just simply being Y.

If the string doesn’t end in Y, there’s still a chance Y could be a vowel if it’s the only vowel in the string. We can use a character class that accounts for all the vowels as we did previously, but this time, we’ll use it for exclusionary purposes.

There are different ways to go about this, but I’ll stick with the test method since it was previously discussed. We’ll just use a bang ! so that any time we don’t encounter a vowel, we get true returned.

The second part of this conditional is obvious. If we’ve already confirmed there are no other vowels, Y has to be present in the word to count as a vowel. We can use the includes method to tell if it’s present.

Accounting for terminating special characters

Now that we’ve accounted for Y as a vowel, you’d think we could just move on and alter our other functions to incorporate this new functionality. That’s true, and it’s initially what I did first.

However, when screwing around with this algorithm, I realized something. YIsAVowel looks specifically for the character at the end of the string as part of its logic.

This does not necessarily mean the last character is a letter. For example, in the word “Happy!” the exclamation point is the last character of that string.

With the way YIsAVowel currently runs, it’s not going to remove the terminal Y from strings that have any sort of punctuation, special characters, or numbers at the end.

Enter the function cutEndPunc. This does exactly what it says on the tin, it will take in an argument of a string, and returns it without any ending punctuation.

You’ll see what looks like a complicated regex in this function. It’s really not that bad when you recognize it’s a character class like anything else.

Regular expressions have some special characters that require the escape notation when being considered an actual character, hence the large number of backslashes.

For readability, this regex could be altered in the future (look into character classes and special characters, the $ in particular), but all you really need to take away from it is that it will remove pretty much anything that’s not a letter from the end of a string.

We’ll use this regex to compare it to the last character of the string cutEndPunc will take as an argument.

Every time it runs into one of the characters in the regex, we’ll shorten the string’s length by 1 using substring manipulation and variable redeclaration.

We’ll take advantage of recursion here so that this activity repeats until no more undesirable characters are at the end of the string.

Modifying established helper functions

Now, we can go back and incorporate this functionality into YIsAVowel.

All that’s different here is that we’ve cut off all the terminal non-letter characters from the string. With that taken care of, all that’s left is modifying our already-established code.

Altering hasVowels to account for Y

The function that checks if a string has vowels needs some minor tweaks now that Y isn’t allowed to be a vowel carte blanche.

First, we just remove the Y from the regex character class. This is still really useful to us because we account for all the other vowels before we even have to think about Y.

However, there will be some point where there are no other vowels and Y is the only contender. This is where we add an extra else if conditional, which checks if the string has Y in it and if Y is a vowel in that string.

If this is false, we can affirm that the string has no vowels in it whatsoever. Then, we can use hasVowels just like we did before.

Altering vowelCut

The last thing we need to do is alter vowelCut to account for the new functionality we’ve introduced. The first part of this code (identifying valid strings) is exactly the same, so let’s jump into the new stuff.

Removing Y as a vowel

This time, instead of splitting the string into individual characters, we’re instead going to split into words.

This is because Y is no longer easy to identify as a vowel. Before, any time we saw it, we cut it out. Now, we have logic where Y may or may not be a vowel in the context of the word it resides in.

Now, we check if every word has Y in it via regex. If it doesn’t, we don’t modify the word in any way. If it does, then we check if Y is a vowel in that word. If it is, we use the replace function.

This function checks for a particular regex (first argument) and replaces it with a string (second). In our case, that means we look for Y and replace it with an empty string. After that’s done, we join the string back up.

Removing all other vowels

We now have a string that has all the vowel-Y’s removed. Any other Y in the string must therefore not be a vowel.

Now, we can do exactly what we did before: split the string into individual characters, and remove any character that is a vowel.

Improved functionality complete

If you’ve gotten to this point, you’ve seen how the process for modifying an algorithm would go.

We still consider endpoints with each new piece of functionality, and while making entirely new methods is still somewhat arduous, incorporating them into already established code isn’t so bad.

This article is very thorough, and with the GitHub repo, you should have no problem seeing how everything is set up.

You’re free to play with it however you want — there’s definitely always things that could be improved to optimize its efficiency, readability, and functionality.

Doing so will no doubt serve as a great way to exercise your analytical thinking and JavaScript abilities.

As always, have fun, and happy coding!

Better Programming

Advice for programmers.

Matt Cummings

Written by

Better Programming

Advice for programmers.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade