C# string e StringBuilder

Esta é a página de consulta dos textos no C#: todos os métodos de string que você vai usar no dia a dia e os do StringBuilder, cada um com exemplo e resultado. Para aprender com calma, veja as aulas Strings, Métodos de String, Interpolação e StringBuilder.

Os resultados vêm dos programas desta página, rodados no dotnet 10.0.112 da máquina da Ana (pasta ~/cs/str, cultura pt-BR) e no editor do guia, que deram a mesma saída (a não ser numa linha do rastro de uma exceção, indicada abaixo).

Atalhos: A string não muda · Métodos de string · Métodos de string. · Comparar e ordenar · char · StringBuilder · string ou StringBuilder? · Quando dá errado · Experimente


Antes de tudo: a string não muda

Nenhum método de string muda o texto original. ToUpper, Trim, Replace e todos os outros devolvem uma string nova. Se você não guardar o resultado, ele se perde:

string nome = "ana";
nome.ToUpper();
Console.WriteLine(nome);
nome = nome.ToUpper();
Console.WriteLine(nome);
$ dotnet run imut.cs
ana
ANA

A linha 2 criou "ANA" e jogou fora; só a linha 4, que guarda o resultado em nome, mudou o que a variável mostra. Essa regra (a string é imutável) é o motivo de existir o StringBuilder, no fim desta página.

Métodos de string

Este programa usa os métodos mais comuns. Cada linha da saída começa com o número da linha da tabela:

// metodos.cs — os métodos de string mais usados
string s = "  Ana Maria da Silva  ";
string nome = "Ana Maria";
Console.WriteLine($"1  [{s.Trim()}] [{s.TrimStart()}] [{s.TrimEnd()}]");
Console.WriteLine($"2  {nome.Length} {nome[0]} {nome[^1]} {nome[4..9]}");
Console.WriteLine($"3  {nome.ToUpper()} {nome.ToLower()} {"ação".ToUpper()}");
Console.WriteLine($"4  {nome.Contains("Maria")} {nome.Contains("maria")} {nome.Contains("maria", StringComparison.OrdinalIgnoreCase)}");
Console.WriteLine($"5  {nome.StartsWith("Ana")} {nome.EndsWith("ia")} {nome.IndexOf('a')} {nome.LastIndexOf('a')} {nome.IndexOf("Maria")} {nome.IndexOf("José")}");
Console.WriteLine($"6  {nome.Substring(4)} | {nome.Substring(0, 3)} | {nome.Replace("Maria", "Clara")} | {nome.Replace('a', 'o')}");
Console.WriteLine($"7  {nome.Insert(3, " Paula")} | {nome.Remove(3)} | {nome.Remove(0, 4)}");
Console.WriteLine($"8  [{"7".PadLeft(3, '0')}] [{"Ana".PadRight(6)}] [{"Ana".PadLeft(6)}]");
string[] partes = "arroz,feijão,,ovos".Split(',');
Console.WriteLine($"9  {partes.Length} [{string.Join("|", partes)}]");
string[] limpas = "arroz, feijão,, ovos".Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
Console.WriteLine($"10 {limpas.Length} [{string.Join("|", limpas)}]");
Console.WriteLine($"11 {string.Concat("a", "b", "c")} {string.Join(", ", ["x", "y", "z"])} {string.Format("{0} tem {1} anos", "Ana", 29)} {new string('-', 5)}");
Console.WriteLine($"12 {string.IsNullOrEmpty("")} {string.IsNullOrEmpty(" ")} {string.IsNullOrWhiteSpace(" ")} {string.IsNullOrWhiteSpace(null)}");
Console.WriteLine($"13 {"ana" == "Ana"} {"ana".Equals("Ana", StringComparison.OrdinalIgnoreCase)} {string.Compare("abacate", "banana")} {string.Compare("b", "a")} {"a".CompareTo("a")}");
char[] letras = nome.ToCharArray();
Array.Reverse(letras);
Console.WriteLine($"14 {new string(letras)} {string.Join("-", nome.Split(' '))} {nome.Count(c => c == 'a')}");
Console.WriteLine($"15 {"maçã".Length} {"🍎".Length} {"olá"[2]} {(int)'á'} {char.IsLetter('á')} {char.IsDigit('7')} {char.ToUpper('é')}");
Console.WriteLine($"16 {"Olá".PadRight(5, '.')}{"Mundo"} {"abc".IndexOfAny(['x', 'b'])} {"a-b-c".Split('-', 2)[1]}");
$ dotnet run metodos.cs
1  [Ana Maria da Silva] [Ana Maria da Silva  ] [  Ana Maria da Silva]
2  9 A a Maria
3  ANA MARIA ana maria AÇÃO
4  True False True
5  True True 2 8 4 -1
6  Maria | Ana | Ana Clara | Ano Morio
7  Ana Paula Maria | Ana | Maria
8  [007] [Ana   ] [   Ana]
9  4 [arroz|feijão||ovos]
10 3 [arroz|feijão|ovos]
11 abc x, y, z Ana tem 29 anos -----
12 True False True True
13 False True -1 1 0
14 airaM anA Ana-Maria 3
15 4 2 á 225 True True É
16 Olá..Mundo 1 b-c

Nas tabelas, nome é "Ana Maria" e s é " Ana Maria da Silva " (com dois espaços nas pontas).

Tamanho, posições e pedaços

MembroO que fazExemploResultadoAula
Lengthquantos caracteres (propriedade, sem parênteses)nome.Length9Strings
[i]o caractere da posição i (do 0); é um charnome[0] · nome[^1]A · aStrings
[a..b]o pedaço da posição a até antes de bnome[4..9]MariaÍndices e Intervalos
Substring(início)do início até o fimnome.Substring(4)MariaMétodos de String
Substring(início, tamanho)tamanho caracteres a partir do inícionome.Substring(0, 3)AnaMétodos de String
IndexOf(x)a primeira posição de x (char ou texto), ou -1nome.IndexOf('a') · nome.IndexOf("Maria") · nome.IndexOf("José")2 · 4 · -1Métodos de String
LastIndexOf(x)a última posiçãonome.LastIndexOf('a')8Métodos de String
IndexOfAny(chars)a primeira posição de qualquer um dos caracteres"abc".IndexOfAny(['x', 'b'])1Métodos de String

Repare no IndexOf('a'): o A maiúsculo da posição 0 não conta. Maiúsculas e minúsculas são caracteres diferentes.

Procurar

MétodoPerguntaExemploResultado
Contains(x)tem x em algum lugar?nome.Contains("Maria") · nome.Contains("maria")True · False
Contains(x, StringComparison.OrdinalIgnoreCase)o mesmo, ignorando maiúsculasnome.Contains("maria", StringComparison.OrdinalIgnoreCase)True
StartsWith(x)começa com x?nome.StartsWith("Ana")True
EndsWith(x)termina com x?nome.EndsWith("ia")True

Aula: Métodos de String. Para procurar padrões (um CPF, um e-mail), veja Expressões Regulares.

Transformar (sempre devolvem uma string nova)

MétodoO que fazExemploResultado
Trim()tira espaços (e Tab, Enter) das duas pontass.Trim()[Ana Maria da Silva]
TrimStart(), TrimEnd()só do começo, só do fims.TrimStart() · s.TrimEnd()[Ana Maria da Silva ] · [ Ana Maria da Silva]
ToUpper(), ToLower()maiúsculas, minúsculas (com acentos, na cultura atual)nome.ToUpper() · "ação".ToUpper()ANA MARIA · AÇÃO
Replace(velho, novo)troca todas as ocorrênciasnome.Replace("Maria", "Clara") · nome.Replace('a', 'o')Ana Clara · Ano Morio
Insert(posição, texto)põe o texto na posiçãonome.Insert(3, " Paula")Ana Paula Maria
Remove(início), Remove(início, quantos)tira do início até o fim, ou só quantosnome.Remove(3) · nome.Remove(0, 4)Ana · Maria
PadLeft(n, c), PadRight(n, c)completa até n caracteres com c (espaço, se omitido)"7".PadLeft(3, '0') · "Ana".PadRight(6) · "Olá".PadRight(5, '.')[007] · [Ana ] · Olá..
ToCharArray()vira um array de charArray.Reverse(letras) e new string(letras)airaM anA

Aulas: Métodos de String e, para alinhar números, Formatar Números.

Cortar e juntar

MétodoO que fazExemploResultado
Split(c)corta em cada c e devolve um string[]; pedaços vazios ficam"arroz,feijão,,ovos".Split(',')4 pedaços: arroz|feijão||ovos
Split(c, opções)RemoveEmptyEntries tira os vazios; TrimEntries tira os espaços de cada pedaço .NET 5"arroz, feijão,, ovos".Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)3 pedaços: arroz|feijão|ovos
Split(c, n)no máximo n pedaços; o último fica com o resto"a-b-c".Split('-', 2)[1]b-c
string.Join(sep, itens)junta, com sep entre os itensstring.Join("-", nome.Split(' '))Ana-Maria

Métodos de string. (chamados pelo tipo)

MétodoO que fazExemploResultadoAula
string.IsNullOrEmpty(s)null ou ""?string.IsNullOrEmpty("") · (" ")True · Falsenull
string.IsNullOrWhiteSpace(s)null, vazio ou só espaços? (o melhor para validar o que foi digitado)string.IsNullOrWhiteSpace(" ") · (null)True · True
string.Join(sep, itens)juntastring.Join(", ", ["x", "y", "z"])x, y, zMétodos de String
string.Concat(…)junta sem separadorstring.Concat("a", "b", "c")abcStrings
string.Format(modelo, …)preenche {0}, {1}… (a forma antiga da interpolação)string.Format("{0} tem {1} anos", "Ana", 29)Ana tem 29 anosInterpolação
new string(c, n)o caractere c repetido n vezesnew string('-', 5)-----Strings
string.Emptyo mesmo que ""string vazio = string.Empty;""Strings

Comparar e ordenar

// comparar.cs — comparar e ordenar textos
string[] nomes = ["bruno", "Ana", "álvaro", "Carla", "ana"];
Console.WriteLine(string.Join(" ", nomes.Order()));
Console.WriteLine(string.Join(" ", nomes.Order(StringComparer.Ordinal)));
Console.WriteLine($"{string.Compare("a", "B")} {string.Compare("a", "B", StringComparison.Ordinal)}");
Console.WriteLine($"{"Ana".Equals("ana")} {string.Equals("Ana", "ana", StringComparison.OrdinalIgnoreCase)}");
$ dotnet run comparar.cs
álvaro ana Ana bruno Carla
Ana Carla ana bruno álvaro
-1 31
False True
FormaCompara comoExemploResultado
a == b, a.Equals(b)caractere por caractere, maiúsculas contam"ana" == "Ana"False
string.Equals(a, b, StringComparison.OrdinalIgnoreCase)ignorando maiúsculas"ana".Equals("Ana", StringComparison.OrdinalIgnoreCase)True
string.Compare(a, b), a.CompareTo(b)ordem de dicionário na cultura atual: negativo se a vem antes, 0 se igual, positivo se depoisstring.Compare("abacate", "banana") · ("b", "a") · "a".CompareTo("a")-1 · 1 · 0
StringComparison.Ordinalpelo código de cada caractere: todas as maiúsculas antes das minúsculas, e os acentos depois de tudostring.Compare("a", "B", StringComparison.Ordinal)31 (positivo: a vem depois de B)

Na ordem do dicionário (a primeira linha da saída), álvaro fica junto dos a, e ana vem antes de Ana. Na ordem Ordinal (a segunda), as maiúsculas vêm primeiro e o á vai para o fim. Use a cultura para mostrar listas para pessoas e Ordinal para comparar códigos, nomes de arquivo e chaves. Aula: Cultura.

O tipo char

ExpressãoResultadoObservação
"maçã".Length4cada letra acentuada é um char
"🍎".Length2um emoji ocupa dois char (UTF-16)
"olá"[2]áum char
(int)'á'225o código Unicode do caractere
char.IsLetter('á'), char.IsDigit('7')True, Truetambém IsWhiteSpace, IsUpper, IsLower, IsPunctuation
char.ToUpper('é')Étambém char.ToLower
nome.Count(c => c == 'a')3uma string é uma sequência de char: aceita LINQ

Aula: char e bool.


StringBuilder

O StringBuilder (de System.Text) é um texto que muda: cada Append acrescenta no mesmo objeto, sem criar uma string nova. É o certo para montar um texto em muitos pedaços, num laço.

// sb.cs — StringBuilder
using System.Text;

StringBuilder sb = new();
sb.Append("Lista de compras");
sb.AppendLine(":");
foreach (string item in new[] { "arroz", "feijão", "café" })
{
    sb.Append("- ").AppendLine(item);
}
sb.AppendLine($"Total: {3} itens");
Console.Write(sb.ToString());
Console.WriteLine($"Length: {sb.Length}");

sb.Clear();
sb.Append("Ana");
sb.Insert(0, "Sra. ");
sb.Append('!', 3);
sb.Replace("Ana", "Ana Maria");
Console.WriteLine(sb);
sb.Remove(0, 5);
Console.WriteLine(sb);
sb[0] = 'a';
Console.WriteLine($"{sb} {sb.Length} {sb[0]}");
$ dotnet run sb.cs
Lista de compras:
- arroz
- feijão
- café
Total: 3 itens
Length: 57
Sra. Ana Maria!!!
Ana Maria!!!
ana Maria!!! 12 a
MembroO que fazExemploAula
new StringBuilder()cria vazio (também new StringBuilder("começo"))StringBuilder sb = new();StringBuilder
Append(x)acrescenta no fim (texto, número, char…); devolve o próprio sb, então dá para encadearsb.Append("- ").AppendLine(item);
Append(c, n)acrescenta o caractere c n vezessb.Append('!', 3);
AppendLine(x)acrescenta e quebra a linha (AppendLine() só quebra)sb.AppendLine(":");
Insert(posição, x)põe na posiçãosb.Insert(0, "Sra. ");
Replace(velho, novo)troca todas as ocorrências, no próprio sbsb.Replace("Ana", "Ana Maria");
Remove(início, quantos)tira caracteressb.Remove(0, 5);
Clear()esvaziasb.Clear();
Lengthquantos caracteres tem agora (dá para mudar: sb.Length = 0 também esvazia)sb.Length → 57
[i]lê e muda um caractere (na string não dá)sb[0] = 'a';
ToString()a string prontastring texto = sb.ToString();
Console.WriteLine(sb)chama o ToString() sozinhoConsole.WriteLine(sb);

string ou StringBuilder?

SituaçãoUsePor quê
Juntar poucos pedaços numa linhainterpolação: $"{nome} tem {idade} anos"mais legível; o compilador já otimiza
Juntar os itens de uma lista com separadorstring.Join(", ", itens)uma chamada só, sem laço
Montar um texto num laço, pedaço por pedaço (um relatório, um arquivo)StringBuildercom += num laço, cada volta copia o texto inteiro para uma string nova; com milhares de voltas, fica muito mais lento
Comparar, procurar, cortarstringo StringBuilder não tem Contains, Split, IndexOf: faça ToString() antes

Quando dá errado

CódigoMensagem real (lab)O que significa e como consertarAula
nome[0] = 'A';error CS0200: A propriedade ou o indexador "string.this[int]" não pode ser atribuído, pois é somente leituraA string não muda. Crie outra: nome = char.ToUpper(nome[0]) + nome[1..];, ou use um StringBuilder.Strings
char inicial = 'An';error CS1012: Número excessivo de caracteres no literal de caractereAspas simples são para um caractere. Texto vai em aspas duplas: string inicial = "An";char e bool
int idade = "29";error CS0029: Não é possível converter implicitamente tipo "string" em "int""29" é texto. Converta: int.Parse("29") ou, com o que o usuário digita, int.TryParse.Parse e TryParse
"Ana".Substring(1, 5)System.ArgumentOutOfRangeException: Index and length must refer to a location within the string. (Parameter 'length')"Início e tamanho têm de caber na string": a partir da posição 1 só há 2 caracteres. Confira o Length antes, ou use [1..].Métodos de String
"Ana"[3]System.IndexOutOfRangeException: Index was outside the bounds of the array.As posições de "Ana" vão de 0 a 2. A mensagem fala em "array" mesmo sendo uma string. No lab, o rastro mostra também a linha at System.String.get_Chars(Int32 index); o editor do guia não mostra essa linha.Strings
string? apelido = null;
apelido.Length
warning CS8602: Desreferência de uma referência possivelmente nula. e, ao rodar, System.NullReferenceException: Object reference not set to an instance of an object.O compilador avisou, e o programa caiu. Use apelido?.Length ou confira is null antes.Referências Anuláveis
nome.ToUpper(); sozinho(compila, sem aviso, e não muda nada)Guarde o resultado: nome = nome.ToUpper();. Veja a missão abaixo.Métodos de String

Experimente

Missão: o programa deveria limpar os espaços e pôr o nome em maiúsculas, mas mostra [ ana ]. Conserte as linhas 2 e 3 para a saída ser [ANA].

string nome = "  ana  ";
nome.Trim();
nome.ToUpper();
Console.WriteLine($"[{nome}]");
string nome = "  ana  ";
nome = nome.Trim();
nome = nome.ToUpper();
Console.WriteLine($"[{nome}]");

Experimente: troque o texto e os métodos e veja o resultado. Tente Replace, Split com outro separador, PadLeft…

string frase = "  A Ana ama arroz com feijão  ";
Console.WriteLine($"[{frase.Trim()}]");
Console.WriteLine(frase.Trim().ToUpper());
Console.WriteLine(frase.Contains("arroz"));
Console.WriteLine(frase.Trim().Split(' ').Length);
Console.WriteLine(frase.Replace("arroz", "macarrão").Trim());
Console.WriteLine(frase.Count(c => c == 'a'));

Resumo

  • A string é imutável: todo método devolve uma string nova. Guarde o resultado.
  • Length e [i] (do 0); pedaços com Substring ou [a..b]; posições com IndexOf (-1 = não achou).
  • Trim, ToUpper, ToLower, Replace, PadLeft, Insert, Remove transformam; Contains, StartsWith, EndsWith perguntam.
  • Split corta (com RemoveEmptyEntries e TrimEntries); string.Join junta.
  • Para validar entrada, string.IsNullOrWhiteSpace. Para comparar sem ligar para maiúsculas, StringComparison.OrdinalIgnoreCase.
  • Muitos pedaços num laço: StringBuilder com Append/AppendLine e, no fim, ToString().