2

I'm trying to write a javascript function that receives a string, and counts the amount of vowels. Displaying the count of each vowel, as well as a grand total. It works fine if every vowel is in the string, but if for example there aren't an A's or E's, it will return null.

Is there a way I can intercept this and replace null's with 0? Or is there a more efficient way to achieve this? Thank you to anyone who can help!

function countVowels(inString) {
  return outString = (
    "Total vowels: " + inString.match(/[aeiou]/gi).length +
    "\nTotal A's: " + inString.match(/[a]/gi).length +
    "\nTotal E's: " + inString.match(/[e]/gi).length +
    "\nTotal I's: " + inString.match(/[i]/gi).length +
    "\nTotal O's: " + inString.match(/[o]/gi).length +
    "\nTotal U's: " + inString.match(/[u]/gi).length
  );
}
<form>
  Enter a string to count its vowels. <br>
  <input type="text" id="inString"><br>
  <button type="button" onclick="console.log(countVowels(inString.value))">Count vowels</button>
</form>

2
  • Yeah, match is kind of annoying that way. I’d try a different approach: writing a function count(string, letter) that counts the number of instances of letter in string, and calling it with count(inString, 'a'), count(inString, 'e'), etc.. You can save each of those and add them together to get the total number of vowels. Commented Oct 12, 2017 at 7:14
  • Instead of /[a]/gi, you can use /a/gi. This won't solve your issue, but it's a little cleaner... Commented Oct 12, 2017 at 7:17

3 Answers 3

7

You can use || [] as a default "return value" in case .match returns null:

function countVowels(inString) {
  return outString = (
    "Total vowels: " + (inString.match(/[aeiou]/gi) || []).length +
    "\nTotal A's: " + (inString.match(/a/gi) || []).length +
    "\nTotal E's: " + (inString.match(/e/gi) || []).length +
    "\nTotal I's: " + (inString.match(/i/gi) || []).length +
    "\nTotal O's: " + (inString.match(/o/gi) || []).length +
    "\nTotal U's: " + (inString.match(/u/gi) || []).length
  );
}
<form>
  Enter a string to count its vowels. <br>
  <input type="text" id="inString"><br>
  <button type="button" onclick="console.log(countVowels(inString.value))">Count vowels</button>
</form>

Also, notice I removed the [] from all single-character matches. In regexes, [a] and a are equivalent.

The || will return the left side of the operator if that side is "truthy".
If the left side is "falsy", the || will always return the right side of the statement, which is our default value.

If the .match finds any results, it returns an array, which is "truthy".
If the .match does not find any results, it returns null, which is "falsy".

Sign up to request clarification or add additional context in comments.

1 Comment

In case someone comes across this answer while searching for a way to return the match or a default value, this is the way to do it in a one-liner: (myString.match(<the matching pattern>) || ['', 'the default value'])[1].
1

Issue is not in regex but in logic.

For a given inString say test, it does not have vowel a or o. So the regex will not find any match and this will fail.

You can try something like this:

Original Code:

function countVowels(inString) {
  return outString = (
    "Total vowels: " + (inString.match(/[aeiou]/gi) || []).length +
    "\nTotal A's: " + (inString.match(/[a]/gi) || []).length +
    "\nTotal E's: " + (inString.match(/[e]/gi) || []).length +
    "\nTotal I's: " + (inString.match(/[i]/gi) || []).length +
    "\nTotal O's: " + (inString.match(/[o]/gi) || []).length +
    "\nTotal U's: " + (inString.match(/[u]/gi) || []).length
  );
}
<form>
  Enter a string to count its vowels. <br>
  <input type="text" id="inString"><br>
  <button type="button" onclick="console.log(countVowels(inString.value))">Count vowels</button>
</form>

Updated Code

function countVowels(inString) {
  var vowels = "aeiou";
  var ret = "Total vowels: " + getMatchLength(inString, vowels);
  for(var i = 0; i< vowels.length; i++)
    ret += "\nTotal " + vowels[i].toUpperCase() + "'s: " + getMatchLength(inString, vowels[i])
  return ret;
}

function getMatchLength(str, chars) {
  return (str.match(new RegExp("["+ chars + "]")) || []).length;
}
<form>
  Enter a string to count its vowels. <br>
  <input type="text" id="inString"><br>
  <button type="button" onclick="console.log(countVowels(inString.value))">Count vowels</button>
</form>

Comments

-1

You can add use conditional operator to output 0 instead of length when the result of match is null.

To make it more readable, you can get the lengths beforehand and then use it in your final string.

function countVowels(inString) {
  var aCount = inString.match(/[a]/gi) !== null ? inString.match(/[a]/gi).length : 0;
  
  var eCount = inString.match(/[e]/gi) !== null ? inString.match(/[a]/gi).length : 0;
  
  var iCount = inString.match(/[i]/gi) !== null ? inString.match(/[a]/gi).length : 0;
  
  var oCount = inString.match(/[o]/gi) !== null ? inString.match(/[a]/gi).length : 0;
  
  var uCount = inString.match(/[u]/gi) !== null ? inString.match(/[a]/gi).length : 0;
  
  var vowelsCount = aCount + eCount + iCount + oCount + uCount;
  
  var outString = "Total vowels: " + vowelsCount + 
  "\nTotal A's: " + aCount + 
  "\nTotal E's: " + eCount + 
  "\nTotal I's: " + iCount + 
  "\nTotal O's: " + oCount + 
  "\nTotal U's: " + uCount;
  
  return outString;
}
<form>
 Enter a string to count its vowels. <br>
 <input type="text" id="inString"><br>
 <button type="button" onclick="console.log(countVowels(inString.value))">Count vowels</button>
 </form>

2 Comments

this is kind of wasteful, since you're executing every regex match twice.
@TimothyGroote yes, you're right. Just checked Cerbrus's answer below. Thanks for pointing out.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.