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".Lengthresulta 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")retornatrue. - 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.