Substring restituisce una nuova stringa formata da una parte di una stringa esistente. Ha due overload:
s.Substring(startIndex): dastartIndexfino alla fine.s.Substring(startIndex, length):lengthcaratteri, a partire dastartIndex.
Gli indici partono da 0, e il secondo argomento è una lunghezza, non una posizione finale. È questa la differenza rispetto a substring(start, end) di JavaScript e substring(begin, end) di Java, e l'origine di molti bug di qualche carattere in più o in meno quando si porta il codice.
Output:
4271-BLK
SHOE
4271
BLK
0
SHOE-4271-BLK
Come ogni metodo delle stringhe, Substring non modifica l'originale; restituisce una nuova stringa, quindi assegna il risultato.
ArgumentOutOfRangeException e come evitarla
Substring lancia ArgumentOutOfRangeException quando l'intervallo richiesto non sta dentro la stringa: uno startIndex negativo, uno startIndex maggiore di Length, una length negativa, oppure startIndex + length maggiore di Length. Non c'è alcun troncamento silenzioso, a differenza degli slice di Python.
Output:
Substring(2, 4) -> "ffee"
Substring(2, 5) -> ArgumentOutOfRangeException
Substring(6) -> ""
Substring(7) -> ArgumentOutOfRangeException
Substring(-1) -> ArgumentOutOfRangeException
Substring(0, 10) -> ArgumentOutOfRangeException
La protezione tipica è limitare la lunghezza a quello che resta della stringa con Math.Min:
Output:
ffee
ea
[]
[]
Chiamare Substring su una stringa null lancia NullReferenceException, non ArgumentOutOfRangeException, ed è per questo che il metodo di supporto controlla prima il null.
Primi e ultimi n caratteri
Prendere un prefisso o un suffisso è l'uso più comune di Substring. Entrambi lanciano un'eccezione quando la stringa è più corta di n, quindi il codice di produzione controlla la lunghezza:
Output:
**** 1111
An Unexpecte...
Hi
Hi
Quando vuoi eliminare la prima parte della stringa, basta Substring(n) da solo: "#FF8800".Substring(1) è "FF8800". Il metodo affine Remove(start, count) fa l'inverso di Substring: restituisce la stringa senza quell'intervallo.
Substring con IndexOf
La maggior parte delle sottostringhe reali si trova, non si conta. IndexOf restituisce la posizione di un carattere o di una stringa (oppure -1 se non c'è), e LastIndexOf cerca partendo dalla fine. Combinali con Substring per tagliare il testo attorno a un separatore:
Output:
maya.lopez
example.com
pdf
report.final.v2
WARN
Disk almost full
Il calcolo segue una sola regola: per prendere il testo tra le posizioni a e b (escluse entrambe), l'inizio è a + 1 e la lunghezza è b - a - 1.
Il pericolo è IndexOf che restituisce -1. email.Substring(0, -1) lancia un'eccezione e, peggio ancora, email.Substring(-1 + 1) restituisce silenziosamente l'intera stringa. Controlla sempre:
Output:
shop.io
(none)
Split come alternativa
Quando una stringa è un elenco di campi con un separatore, Split è più semplice di una catena di chiamate a IndexOf e Substring, e non ha calcoli sugli indici da sbagliare:
Output:
Ana Silva
Porto
maya.lopez
beach.jpg
Split alloca un array più una stringa per campo, quindi per un singolo taglio in un ciclo critico IndexOf e Substring costano meno. In tutti gli altri casi vince la leggibilità. Altre opzioni (più separatori, rimozione delle voci vuote, un numero massimo di parti) sono in metodi delle stringhe. Per pattern come "le cifre dopo ID:", un'espressione regolare è di solito lo strumento più chiaro.
L'operatore di intervallo (C# 8 e successivi)
C# 8 ha aggiunto la sintassi di indici e intervalli, che funziona su stringhe e array. ^n significa "n dalla fine" e a..b è l'intervallo da a fino a b escluso, quindi il secondo numero è un indice finale, non una lunghezza:
// 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'
Su una stringa, un intervallo viene compilato in una chiamata a Substring, quindi alloca una nuova stringa e lancia ArgumentOutOfRangeException negli stessi casi fuori dai limiti. Quale usare è questione di stile; gli intervalli si leggono meglio quando i due estremi sono misurati da lati diversi ([1..^1]).
Sottostringhe senza copia: Span
Ogni chiamata a Substring alloca una nuova stringa. Nel codice di parsing dove contano le prestazioni (lettura di file grandi, gestione di molte richieste), .NET Core 2.1 e successivi offrono ReadOnlySpan<char>, una vista su una parte della stringa originale senza copia:
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);
Gli span non possono essere salvati nei campi delle classi normali né usati a cavallo di un await, quindi appartengono al codice sincrono e compatto. Per il normale codice applicativo, Substring è lo strumento giusto.
Errori comuni
- Passare un indice finale come lunghezza.
s.Substring(2, 5)significa cinque caratteri dall'indice 2, non "dall'indice 2 al 5". Per prendere il testo dall'indiceafino all'indicebescluso, la lunghezza èb - a. - Non controllare se
IndexOfrestituisce -1. Il risultato è un'eccezione oppure, con+ 1, l'intera stringa per sbaglio. - Dare per scontato che le stringhe corte siano abbastanza lunghe. Un nome, un codice o una riga di un file può essere più corto di quanto pensi. Limita con
Math.Mino controllaLength. - Scartare il risultato.
s.Substring(1);da solo su una riga non fa nulla di utile.
Domande frequenti
Come funziona Substring in C#?
s.Substring(start) restituisce i caratteri dall'indice start fino alla fine; s.Substring(start, length) restituisce length caratteri a partire da start. Gli indici partono da 0, e il secondo argomento è una lunghezza, non un indice finale: "Hello".Substring(1, 3) è "ell". La stringa originale non cambia.
Perché Substring lancia ArgumentOutOfRangeException?
Perché start è negativo o maggiore della lunghezza della stringa, oppure start + length va oltre la fine. La causa più comune è una lunghezza calcolata per una stringa più lunga, o un risultato -1 di IndexOf usato come inizio. Limita la lunghezza con Math.Min(length, s.Length - start) e controlla i risultati di IndexOf prima di usarli.
Come ottengo gli ultimi n caratteri di una stringa in C#?
s.Substring(s.Length - n) restituisce gli ultimi n caratteri, purché n <= s.Length. Per non fallire con le stringhe corte, usa s.Length <= n ? s : s.Substring(s.Length - n). Da C# 8 in poi puoi anche scrivere s[^n..], che lancia la stessa eccezione quando n è troppo grande.
Come ottengo il testo tra due caratteri in C#?
Trova le due posizioni con IndexOf, poi prendi la parte che sta in mezzo: int start = s.IndexOf('(') + 1; int end = s.IndexOf(')', start); string inside = s.Substring(start, end - start);. Controlla che ogni IndexOf abbia trovato qualcosa (non -1) prima di chiamare Substring. Per pattern complessi, un'espressione regolare è più chiara.
Substring parte da zero in C#?
Sì. Il primo carattere è all'indice 0 e l'ultimo a Length - 1. Substring(0, 3) restituisce i primi tre caratteri. Passare proprio Length come inizio è consentito e restituisce una stringa vuota.