Quantas vezes a letra «a» aparece na palavra «abracadabra»? Resolvendo o problema em C#
Imagine: você está escrevendo um analisador de logs, analisando um arquivo CSV ou apenas verificando quantas vezes o usuário digitou o caractere @ em um e-mail. A tarefa de «contar o número de ocorrências de um caractere ou substring em uma string» é uma daquelas que aparece em cada segundo projeto. No Stack Overflow, esta pergunta reuniu milhares de visualizações e dezenas de respostas. Não é surpresa: em C# existem pelo menos 5 maneiras diferentes, e escolher a correta pode economizar horas de depuração.
Neste artigo, abordaremos todos os métodos populares — desde o loop clássico até o moderno Span<T> e LINQ. Você descobrirá qual método é mais rápido, qual é mais legível e qual é melhor não usar em produção. Vamos lá!
1. Loop clássico foreach — o método do avô
A maneira mais intuitiva: pegue a string, percorra cada caractere e conte as correspondências. Funciona sempre, não requer bibliotecas adicionais.
string text = "abracadabra";char target = 'a';int count = 0;
foreach (char c in text){ if (c == target) count++;}
Console.WriteLine($"O caractere '{target}' aparece {count} vez(es)."); // Saída: 4Prós: legibilidade, controle sobre o processo, você pode adicionar lógica (por exemplo, ignorar maiúsculas/minúsculas).
Contras: não é adequado para contar substrings (vários caracteres consecutivos) — para isso, você precisaria escrever um loop aninhado.
2. Método Count() do LINQ — uma linha para caracteres
Se você gosta de código conciso e usa LINQ, esta opção é para você. O método Count() aceita um predicado e retorna o número de elementos que satisfazem a condição.
using System.Linq;
string text = "Hello, World!";char target = 'l';
int count = text.Count(c => c == target);Console.WriteLine(count); // Saída: 3Observe: Count() é um método de extensão do namespace System.Linq. Se você não incluir using System.Linq, o código não será compilado.
Para contar substrings, este método não é adequado diretamente. Você precisará primeiro dividir a string ou usar expressões regulares (veja o item 5).
3. Span<T> e MemoryExtensions — desempenho máximo
Se você trabalha com strings grandes (megabytes de logs) e cada milissegundo conta, esqueça o LINQ. Use Span<char> e o método Count() de MemoryExtensions (disponível a partir do .NET 5+).
using System;
string text = "abracadabra";ReadOnlySpan<char> span = text.AsSpan();int count = span.Count('a');
Console.WriteLine(count); // Saída: 4Por que é rápido? Span<T> trabalha com blocos de memória contíguos sem alocar novos objetos. O método Count() em MemoryExtensions é otimizado para instruções SIMD — ele processa de 16 a 32 caracteres por ciclo de clock da CPU.
Para substrings também há solução:
int count = span.Count("ra"); // conta as ocorrências da substring "ra"Console.WriteLine(count); // Saída: 2 ("abracadabra" contém "ra" duas vezes)Importante: este método diferencia maiúsculas de minúsculas. Se precisar ignorar a diferença, primeiro converta a string para um único caso ou use span.Count("ra", StringComparison.OrdinalIgnoreCase).
4. Método Split — um truque esperto para substrings
Uma maneira antiga, mas funcional: dividir a string pela substring desejada e contar o número de partes menos um.
string text = "um, dois, três, um, quatro";string target = "um";
int count = text.Split(target, StringSplitOptions.None).Length - 1;Console.WriteLine(count); // Saída: 2Como funciona: Split