Manipulação de Strings e Otimização de Memória com StringBuilder em C#

Em C#, o tipo string é fundamental para o armazenamento e processamento de dados textuais. No entanto, devido à sua natureza imutável, é crucial compreender como manipulá-lo eficientemente e quando utilizar alternativas como o StringBuilder para evitar problemas de performance.

Métodos Essenciais da Classe String

Abaixo estão as operações mais frequentes realizadas com strings em C#:

  • Length: Retorna a quantidade de caracteres. Ex: "exemplo".Length resulta em 7.
  • Substring: Extrai uma parte da string. Pode receber apenas o índice inicial ou o índice e o tamanho. Ex: "exemplo".Substring(2, 3) retorna "emp".
  • Contains: Verifica a existência de uma substring, retornanod um booleano. Ex: "exemplo".Contains("emp") retorna true.
  • Replace: Substitui todas as ocorrências de uma string por outra. Ex: "exemplo".Replace("emp", "xyz").
  • ToLower / ToUpper: Convertem o texto para minúsculas ou maiúsculas, respectivamente.
  • Trim: Remove espaços em branco no início e no fim da string.
  • Split: Divide a string em um array com base em um ou mais caracteres separadores.

Formatação com string.Format

O método string.Format permite a construção de textos dinâmicos utilizando marcadores de posição numéricos. Também suporta formatações específicas para tipos como datas e moedas.


string produto = "Notebook";
double valor = 3499.90;
DateTime dataVenda = new DateTime(2023, 10, 25, 14, 30, 0);

// Formatação básica e de tipos específicos
string recibo = string.Format("Produto: {0} | Valor: {1:C} | Data: {2:dd/MM/yyyy HH:mm}", produto, valor, dataVenda);
Console.WriteLine(recibo);

Neste exemplo, {1:C} formata o valor como moeda local, e {2:dd/MM/yyyy HH:mm} formata a data e hora de acordo com o padrão especificado.

Verificação de Sufixo e Divisão de Textos

O método EndsWith é útil para validar extensões de arquivos ou terminações de URLs, enquanto o Split é ideal para processar dados delimitados, como arquivos CSV.


// Verificando extensão de arquivo
string caminhoArquivo = "relatorio_financeiro.xlsx";
bool ehPlanilha = caminhoArquivo.EndsWith(".xlsx"); // Retorna true

// Dividindo uma string delimitada por ponto e vírgula
string dadosBrutos = "azul;verde;amarelo;vermelho";
string[] cores = dadosBrutos.Split(';');
Console.WriteLine(cores[2]); // Imprime "amarelo"

Ao usar o Split, o array resultante é alocado dinamicamente com o tamanho exato necessário, baseado na quantidade de separadores encontrados na string original.

Complexidade de Tempo das Operações

Entender a complexidade algorítmica ajuda a evitar gargalos de performance em aplicações críticas:

  • Length: O(1) - Acesso direto ao tamanho interno armazenado.
  • Substring, Contains, Replace, Trim, ToLower, ToUpper: O(n) - Percorrem a string, onde n é o tamanho do texto.
  • Split: O(n) - Analisa cada caractere para encontrar os delimitadores.
  • Format: O(n + m) - Depende do tamanho da string base e da complexidade da conversão dos argumentos.

Otimização de Memória com StringBuilder

Como as strings em C# são imutáveis, operações consecutivas de concatenação geram novos objetos na memória, aumentando a pressão sobre o Garbage Collector (GC). Para cenários que exigem manipulação intensiva de texto, a classe StringBuilder (do namespace System.Text) é a solução ideal, pois utiliza um buffer mutável.

Definir a capacidade enicial do StringBuilder evita realocações de memória desnecessárias durante o crescimento do buffer.


using System;
using System.Text;

public class ExemploStringBuilder
{
    public static void Main()
    {
        // Inicializando com capacidade para evitar realocações frequentes
        StringBuilder buffer = new StringBuilder(64);

        // Construindo uma linha de CSV com cabeçalho e dados
        buffer.Append("ID,Produto,Preco\n");
        buffer.AppendFormat("{0},{1},{2}", 101, "Teclado", 450);

        // Inserindo uma categoria no início da segunda linha (índice 16)
        buffer.Insert(16, "Categoria,");

        // Alterando um caractere específico (trocando vírgula por ponto e vírgula no índice 2)
        buffer[2] = ';';

        // Removendo a primeira linha inteira (16 caracteres)
        buffer.Remove(0, 16);

        // Substituindo o nome do produto
        buffer.Replace("Teclado", "Mouse");

        Console.WriteLine(buffer.ToString());
        Console.WriteLine($"Comprimento: {buffer.Length} | Capacidade: {buffer.Capacity}");
        
        // Limpando o buffer para reutilização sem criar um novo objeto
        buffer.Clear();
    }
}

O buffer interno do StringBuilder dobra de tamanho automaticamente quando a capacidade máxima é atingida, mas definir um valor inicial adeuqado otimiza significativamente o desempenho em loops ou operações massivas de concatenação.

Tags: CSharp String StringBuilder memory-management performance

Publicado em 6-30 17:43