In this article, we will take a closer look at the techniques we can use to count the number of vowels in a string in C#. We will go through the code and learn more about each approach.

To download the source code for this article, you can visit our GitHub repository.

Let’s get started.

Prepare Our Counters Application

First, let’s create a VowelCounters console application and update the Program.cs file:

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!
const string vowels = "AEIOUaeiou";
var vowelsAsSpan = vowels.AsSpan();
var vowelsHash = new HashSet<char>(vowels);
SearchValues<char> vowelsSearchValues = SearchValues.Create(vowelsAsSpan);

const string sentence = "In the vast expanse of the universe, countless galaxies swirl in a cosmic dance," +
                        " each telling a unique story of creation and destruction.";
var sentenceAsSpan = sentence.AsSpan();

Inside the Program.cs file, we store our unique collection of case-insensitive vowels in two variables: vowelsAsSpan and vowelsHash. Next, we define our example sentence in two variables: sentence and sentenceAsSpan. Lastly, we declare a vowelsSearchValues variable with the type of SearchValues<char>.

Now, with our setup done, let’s examine different ways to count vowels within a string.

To learn more about counting occurrences of a single character in C#, we have a great article Counting Occurrences of a Char Within a String in C#

Count the Number of Vowels Using a Loop

When we want to count something in programming, the first thing that often comes to mind is looping or iteration. Let’s see how to accomplish our goal using both for and foreach loops:

public static int CountVowelsUsingForLoop(ReadOnlySpan<char> sentence, ReadOnlySpan<char> vowels)
{
    var total = 0;

    for (var i = 0; i < sentence.Length; i++)
    {
        if (vowels.Contains(sentence[i]))
        {
            total++;
        }
    }

    return total;
}

Here we pass in the string to search as a ReadOnlySpan<char> and a ReadOnlySpan<char> containing our vowels. We then iterate each character of our sentence, checking to see if it is contained within our vowels collection. If it is contained, we increment the total. Finally, we return the total.

We can take the same approach using a foreach loop:

public static int CountVowelsUsingForEachLoop(ReadOnlySpan<char> sentence, ReadOnlySpan<char> vowels)
{
    var total = 0;

    foreach (var c in sentence)
    {
        if (vowels.Contains(c))
        {
            total++;
        }
    }

    return total;
}

In essence, our foreach loop method is identical to the for loop we previously wrote. We loop through each character and increment the total when the character is found within the vowels collection.

Let’s see them in action:

Console.WriteLine("The number of vowels counted using For loop is: " +
    $"{VowelCounters.CountVowelsUsingForLoop(sentenceAsSpan, vowelsAsSpan)}");
Console.WriteLine("The number of vowels counted using ForEach loop is: " +
    $"{VowelCounters.CountVowelsUsingForEachLoop(sentenceAsSpan, vowelsAsSpan)}");

Here we see the results from the two methods:

The number of vowels counted using For loop is: 46
The number of vowels counted using ForEach loop is: 46

Count the Number of Vowels Using SearchValues

In this example, we will use a new type SearchValues that was added in .NET 8 to optimize the performance when searching for values. SearchValues<T> instances are optimized for situations where the same set of values is frequently used for searching:

public static int CountVowelsUsingSearchValues(ReadOnlySpan<char> sentence, SearchValues<char> vowelsSearchValues)
{
    var total = 0;

    for (var i = 0; i < sentence.Length; ++i)
    {
        if (vowelsSearchValues.Contains(sentence[i]))
            ++total;
    }

    return total;
}

We are again using for loop with an if condition that adds to the total vowel count when the character from the sentence is contained in the vowelsSearchValues.

In our Program.cs file we call our function within Console.WriteLine:

Console.WriteLine($"The number of vowels counted using SearchValues is: {VowelCounters.CountVowelsUsingSearchValues(sentenceAsSpan, vowelsSearchValues)}");

When we run the application we see the console output:

The number of vowels counted using SearchValues is: 46

Count the Number of Vowels With a Switch Statement

In our next approach, we will use a switch statement to count vowels in the supplied string:

public static int CountVowelsUsingSwitchStatement(ReadOnlySpan<char> sentence)
{
    var total = 0;
 
    foreach (var c in sentence)
    {
        switch (c)
        {
            case 'A':
            case 'a':
            case 'E':
            case 'e':
            case 'I':
            case 'i':
            case 'O':
            case 'o':
            case 'U':
            case 'u':
                total++;
                break;
            default:
                break;
        }
    }
 
    return total;
}

Since the switch statement is a conditional statement that resembles if-else-if conditions, we first need to supply it with the character for evaluation. So once again we use a foreach loop to iterate over each character of our string. Next, we use the switch statement to check whether the character is a vowel or not. In case of a match, we increment the total. Lastly, we return the count.

So, let’s test it out:

Console.WriteLine($"The number of vowels counted using Switch statement is: {VowelCounters.CountVowelsUsingSwitchStatement(sentence)}");

We get the console output:

The number of vowels counted using Switch statement is: 46

Count the Number of Vowels Using Regex.Count()

Regular expressions are a powerful tool when it comes to matching characters in a string. We can use System.Text.RegularExpressions namespace to enable regular expressions pattern matching and counting the vowels with a one-liner:

[GeneratedRegex(@"[AEIOUaeiou]")]
private static partial Regex _regexVowels();

public static int CountVowelsUsingRegexCount(string sentence)
{
    return _regexVowels().Count(sentence);
}

Instead of passing the collection of vowels as a parameter, we use a Source Generated Regex to match characters from the supplied string. We call Regex.Count() to count the number of matches within the string.

Let’s see it in action:

Console.WriteLine($"The number of vowels counted using RegexCount is: {VowelCounters.CountVowelsUsingRegexCount(sentence)}");

And here we see the expected result:

The number of vowels counted using RegexCount is: 46

Count the Number of Vowels Using Regex.Replace()

Our next approach uses Regex.Replace() and the string.Length property to count vowels:

[GeneratedRegex(@"[^AEIOUaeiou]+")]
private static partial Regex _regexNotVowels();
 
public static int CountVowelsUsingRegexReplaceAndLength(string sentence)
{
    return _regexNotVowels().Replace(sentence, "").Length;
}

We will again use a Source Generated Regex, but this time we define an expression that contains only non-vowels. We then use Replace() to replace all matching sequences with an empty string. The resulting string will contain only vowels, so we simply return its Length to get our vowel count:

Console.WriteLine($"The number of vowels counted using Regex Replace and Length is:{VowelCounters.CountVowelsUsingRegexReplaceAndLength(sentence)}");

We then use the Console.WriteLine to get the console output:

The number of vowels counted using Regex Replace and Length: 46

Count the Number of Vowels Using LINQ

The last approach we will showcase in this article is using LINQ or Language Integrated Query with a lambda function:

public static int CountVowelsUsingLinq(string sentence, HashSet<char> vowels)
{
    return sentence.Count(x => vowels.Contains(x));
}

In this method, we use the Count() method to count the number of elements that satisfy our condition. The condition is a lambda function that checks if our vowel collection contains the character from the supplied string:

Console.WriteLine($"The number of vowels counted using LINQ is: {VowelCounters.CountVowelsUsingLinq(sentence, vowelsHash)}");

Once again we see the expected result:

The number of vowels counted using LINQ is: 46

Comparing the Performance

Different approaches so far differ only in syntax. So to make any worthy conclusion, we need to measure the execution times to get the whole picture. We use the BenchmarkDotNet package to track the performance of our methods:

| Method                                | Mean        | Error    | StdDev   | Ratio | RatioSD | Rank |
|-------------------------------------- |------------:|---------:|---------:|------:|--------:|-----:|
| CountVowelsUsingSearchValues          |    98.34 ns | 0.307 ns | 0.272 ns |  1.00 |    0.00 |    1 |
| CountVowelsUsingSwitchStatement       |   257.18 ns | 4.741 ns | 5.269 ns |  2.61 |    0.06 |    2 |
| CountVowelsUsingForLoop               |   374.66 ns | 5.044 ns | 4.718 ns |  3.81 |    0.05 |    3 |
| CountVowelsUsingForEachLoop           |   391.99 ns | 3.519 ns | 3.119 ns |  3.99 |    0.04 |    4 |
| CountVowelsUsingLinq                  |   760.63 ns | 7.728 ns | 6.454 ns |  7.74 |    0.07 |    5 |
| CountVowelsUsingRegexCount            | 1,099.87 ns | 5.914 ns | 5.243 ns | 11.18 |    0.07 |    6 |
| CountVowelsUsingRegexReplaceAndLength | 1,493.22 ns | 7.293 ns | 6.465 ns | 15.19 |    0.08 |    7 |

The results show us that the SearchValues approach is the fastest, followed by the switch statement. As we would expect, we see that the  for and foreach loop approaches have similar execution times, but unfortunately, they are nearly four times as slow as the SearchValues method. After this, we have our LINQ approach at approximately 6.5x slower. Then rounding out the final positions, we see our approaches using Regular Expressions.

Conclusion

In this article, we discussed several approaches for counting the number of vowels in the string. While there are also notable differences in performance between the methods, we should always consider our use case and code maintainability when choosing a method.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!