Menu

Substring em C#: extrair parte de uma string com segurança

Como String.Substring funciona em C#: os argumentos de índice inicial e tamanho, a ArgumentOutOfRangeException e como evitá-la, extrair texto em volta de resultados do IndexOf, pegar os primeiros ou os últimos n caracteres e o operador de intervalo do C# 8.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

Substring retorna uma nova string feita de parte de uma existente. Ele tem duas sobrecargas:

  • s.Substring(startIndex): de startIndex até o fim.
  • s.Substring(startIndex, length): length caracteres, começando em startIndex.

Os índices começam em 0, e o segundo argumento é um tamanho, não uma posição final. Essa é a diferença para o substring(start, end) do JavaScript e o substring(begin, end) do Java, e a origem de muitos bugs de posição errada quando o código é portado.

Saída:

4271-BLK
SHOE
4271
BLK
0
SHOE-4271-BLK

Como todo método de string, Substring não modifica a original; ele retorna uma string nova, então atribua o resultado.

ArgumentOutOfRangeException e como evitá-la

Substring lança ArgumentOutOfRangeException quando o intervalo pedido não cabe na string: um startIndex negativo, um startIndex maior que Length, um length negativo ou startIndex + length maior que Length. Não há truncamento silencioso, ao contrário das fatias do Python.

Saída:

Substring(2, 4) -> "ffee"
Substring(2, 5) -> ArgumentOutOfRangeException
Substring(6) -> ""
Substring(7) -> ArgumentOutOfRangeException
Substring(-1) -> ArgumentOutOfRangeException
Substring(0, 10) -> ArgumentOutOfRangeException

A proteção usual é limitar o tamanho ao que sobra da string com Math.Min:

Saída:

ffee
ea
[]
[]

Chamar Substring em uma string null lança NullReferenceException, não ArgumentOutOfRangeException, e é por isso que o auxiliar verifica null primeiro.

Os primeiros e os últimos n caracteres

Pegar um prefixo ou um sufixo é o uso mais comum de Substring. Os dois lançam exceção quando a string é mais curta que n, então código de produção verifica o tamanho:

Saída:

**** 1111
An Unexpecte...
Hi
Hi

Quando o que você quer descartar é o começo da string, Substring(n) sozinho basta: "#FF8800".Substring(1) é "FF8800". O método relacionado Remove(start, count) faz o inverso de Substring: retorna a string sem aquele intervalo.

Substring com IndexOf

A maioria das substrings reais é encontrada, não contada. IndexOf retorna a posição de um caractere ou de uma string (ou -1 se não estiver lá), e LastIndexOf busca a partir do fim. Combine-os com Substring para cortar o texto em volta de um separador:

Saída:

maya.lopez
example.com
pdf
report.final.v2
WARN
Disk almost full

A aritmética segue uma regra: para pegar o texto entre as posições a e b (sem incluir nenhuma das duas), o início é a + 1 e o tamanho é b - a - 1.

O perigo é o IndexOf retornar -1. email.Substring(0, -1) lança exceção e, pior, email.Substring(-1 + 1) retorna a string inteira sem aviso. Sempre verifique:

Saída:

shop.io
(none)

Split como alternativa

Quando uma string é uma lista de campos com um separador, Split é mais simples que uma cadeia de chamadas a IndexOf e Substring, e não tem aritmética de índices para errar:

Saída:

Ana Silva
Porto
maya.lopez
beach.jpg

Split aloca um array mais uma string por campo, então para um único corte em um laço crítico IndexOf e Substring são mais baratos. Em todos os outros casos, a legibilidade vence. Mais opções (vários separadores, remover entradas vazias, quantidade máxima) estão em métodos de string. Para padrões como "os dígitos depois de ID:", uma expressão regular costuma ser a ferramenta mais clara.

O operador de intervalo (C# 8 em diante)

O C# 8 adicionou a sintaxe de índices e intervalos, que funciona em strings e arrays. ^n significa "n a partir do fim" e a..b é o intervalo de a até b, sem incluir b, então o segundo número é um índice final, não um tamanho:

// C# 8 and later
string sku = "SHOE-4271-BLK";

string first4 = sku[..4];      // "SHOE"        same as Substring(0, 4)
string middle = sku[5..9];     // "4271"        same as Substring(5, 4)
string last3  = sku[^3..];     // "BLK"         same as Substring(sku.Length - 3)
string noEnds = sku[1..^1];    // "HOE-4271-BL" drop first and last
char lastChar = sku[^1];       // 'K'

Em uma string, um intervalo é compilado como uma chamada a Substring, então aloca uma string nova e lança ArgumentOutOfRangeException nos mesmos casos fora dos limites. Qual usar é questão de estilo; intervalos se leem melhor quando as duas pontas são medidas de lados diferentes ([1..^1]).

Substrings sem cópia: Span

Toda chamada a Substring aloca uma string nova. Em código de parsing sensível a desempenho (ler arquivos grandes, tratar muitas requisições), o .NET Core 2.1 em diante oferece ReadOnlySpan<char>, uma visão de parte da string original sem cópia:

ReadOnlySpan<char> line = "2026-09-24,42.50,EUR".AsSpan();
ReadOnlySpan<char> amount = line.Slice(11, 5);          // "42.50", no allocation
decimal value = decimal.Parse(amount, provider: CultureInfo.InvariantCulture);

Spans não podem ser guardados em campos de classes comuns nem usados através de um await, então pertencem a código síncrono e enxuto. Para código de aplicação típico, Substring é a ferramenta certa.

Erros comuns

  • Passar um índice final como tamanho. s.Substring(2, 5) significa cinco caracteres a partir do índice 2, não "do índice 2 ao 5". Para pegar o texto do índice a até o índice b, sem incluir b, o tamanho é b - a.
  • Não verificar se o IndexOf deu -1. Ou uma exceção ou, com + 1, a string inteira por acidente.
  • Supor que strings curtas são longas o bastante. Um nome, um código ou uma linha de um arquivo pode ser mais curto do que você espera. Limite com Math.Min ou verifique o Length.
  • Descartar o resultado. s.Substring(1); sozinho em uma linha não faz nada útil.

Perguntas frequentes

Como o Substring funciona em C#?

s.Substring(start) retorna os caracteres do índice start até o fim; s.Substring(start, length) retorna length caracteres começando em start. Os índices começam em 0, e o segundo argumento é um tamanho, não um índice final: "Hello".Substring(1, 3) é "ell". A string original não é alterada.

Por que o Substring lança ArgumentOutOfRangeException?

Porque start é negativo ou maior que o tamanho da string, ou start + length passa do fim. A causa mais comum é um tamanho calculado para uma string mais longa, ou um resultado -1 do IndexOf usado como início. Limite o tamanho com Math.Min(length, s.Length - start) e verifique os resultados do IndexOf antes de usá-los.

Como pegar os últimos n caracteres de uma string em C#?

s.Substring(s.Length - n) retorna os últimos n caracteres, desde que n <= s.Length. Para ser seguro com strings curtas, use s.Length <= n ? s : s.Substring(s.Length - n). No C# 8 em diante você também pode escrever s[^n..], que lança exceção do mesmo jeito quando n é grande demais.

Como pegar a substring entre dois caracteres em C#?

Encontre as duas posições com IndexOf e pegue a parte entre elas: int start = s.IndexOf('(') + 1; int end = s.IndexOf(')', start); string inside = s.Substring(start, end - start);. Verifique se cada IndexOf encontrou algo (não -1) antes de chamar Substring. Para padrões complexos, uma expressão regular é mais clara.

O Substring começa do zero em C#?

Sim. O primeiro caractere está no índice 0 e o último em Length - 1. Substring(0, 3) retorna os três primeiros caracteres. Passar o próprio Length como início é permitido e retorna uma string vazia.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR