Formattazione di stringhe in .NET

Se ritieni utile questo articolo, considera la possibilità di effettuare una donazione (il cui importo è a tua completa discrezione) tramite PayPal. Grazie.

Il .NET Framework fornisce una vasta gamma di opzioni per formattare stringhe, così da rappresentare in modo esaustivo i principali tipi (numerici, date, valuta, enumeratori, ecc.)
In questo articolo verranno evidanziati i diversi formati disponibili, fornendo per ciascun caso un esempio esaustivo di utilizzo, così da costituire una valida guida da tenere sempre sottomano.

In particolare verranno fornite indicazioni sugli identificatori di formato per:

Format Item

Tipicamente la formattazione di stringhe è una delle caratteristiche più utilizzate di un linguaggio. In .NET abbiamo diversi metodi che sfruttano la composizione di stringhe tramite l'uso di placeholder (detti anche format item) come ad esempio:

  • String.Format che restituisce la stringa formattata

  • Console.WriteLine che mostra la stringa formattata nella console

  • TextWriter.WriteLine che scrive la stringa formattata in uno stream o in un file

Consideriamo ad esempio l'overload di String.Format seguente:

public static string Format (string format, params Object[] args)

L'elenco di oggetti args rappresenta l'insieme di valori da sostituire ai rispettivi format item che intervallano il testo fisso in ingresso format.

I segnaposto vengono espressi nella forma:

{index[,alignment][:formatString]}

dove:

  • index rappresenta l'indice numerico (che parte da zero) corrispondente all'oggetto nell'elenco degli args.

    Eventuali elementi di args privi di un corrispondente segnaposto non verranno considerati, mentre un eventuale segnaposto privo del corrispondente elemento in args solleverà una runtime exception

  • alignment è un elemento opzionale di tipo intero con segno che indica la larghezza del campo formattato risultante. Il valore risultante sarà allineato alla destra del campo se alignment è positivo o a sinistra se alignment è negativo.

    Se il valore di alignment è inferiore alla lunghezza della stringa formattata il parametro non viene considerato.

  • formatString è un parametro opzionale che specifica il formato per la rappresentazione del singolo format item. Si veda il seguito dell'articolo per la descrizione dei valori ammessi per formatString in funzione del tipo di oggetto che si desidera rappresentare.

    Se formatString viene omesso verrà utilizzato il formato generale ("G")

NOTA: le parentesi graffe sono interpretate come identificatori di placeholder; per rappresentare l'apertuta di una parentesi graffa nel risultato della formattazione è necessario inserire due aperture di parentesi graffe ({{) nel testo fisso format; la gestione dell'escaping della chiusura delle parentesi graffa è analogo a quello per l'apertura della stessa (}} per rappresentare })

Gli oggetti in args verranno rappresentati in formato stringa come:

  1. se null come stringa vuota ("")

  2. se il tipo implementa l'interfaccia ICustomFormatter mediante la chiamata al metodo ICustomFormatter.Format

  3. se il tipo implementa l'interfaccia IFormattable mediante la chiamata al metodo IFormattable.ToString

  4. mediante la chiamata al metodo ToString dell'oggetto (Object.ToString)

L'output di tutti gli esempi che seguono è riferito alle impostazioni internazionali italiane: CultureInfo("it-IT")

DEMO 1

Il seguente codice:

string Name = "Matteo";
Console.WriteLine("I am '{0}'", Name);
Console.WriteLine("I am '{0,10}'", Name);
Console.WriteLine("I am '{0,-10}'", Name);

Produrra:

I am 'Matteo'
I am '    Matteo'
I am 'Matteo    '

Formattazione di tipi numerici

La formattazione di un tipo numerico può essere in forma standard (mediante l'applicazione di uno stile predefinito per il tipo numerico specifico con la possibilità di definirne la precisione) o custom (mediante un formato specificato dall'utente)

Stringhe di formato numerico standard

La formattazione standard prevede la dichiarazione del formato nella forma Ann dove A è un singolo carattere alfabetico che specifica il formato (vedi tabella seguente) e nn è un intero che specifica la precisione (opzionale)

Formato Nome Esempio Output
C (o c) Valuta (currency) String.Format("{0:c}", 123456.789); String.Format("{0:c5}", 123456.789); String.Format("{0:c}", -123456.789); € 123.456,79 € 123.456,78900 -€ 123.456,79
D (o d) Decimale String.Format("{0:d}", 123456); String.Format("{0:d10}", 123456); 123456 0000123456
E (o e) Scientifico (esponenziale) String.Format("{0:e}", 123456.789); String.Format("{0:e10}", 123456.789); 1,234568e+005 12345678900+005
F (o f) A virgola fissa String.Format("{0:f}", 123456.789); String.Format("{0:f5}", 123456.789); 123456,79 123456,78900
G (o g) Generale String.Format("{0:g}", 123456.789); String.Format("{0}", 123456.789); 123456,79 123456,79

Predefinito (le due notazioni d'esempio sono equivalenti).
Il numero viene convertito nel formato più compatto tra la notazione scientifica e quella a virgola fissa, a seconda del tipo di numero e dell'eventuale presenza dell'identificatore di precisione.

N (o n) Numero String.Format("{0:n}", 123456.789); String.Format("{0:n5}", 123456.789); 123.456,79 123.456,78900

Vengono inseriti separatori delle migliaia tra ciascun gruppo di tre cifre a sinistra del separatore decimale.

P (o p) Percentuale String.Format("{0:p}", 0.123456789); String.Format("{0:p}", 123456.789); String.Format("{0:p10}", 0.123456789); 12,35% 12.345.678,90% 12,3456789000%

Il numero convertito viene moltiplicato per 100 in modo da essere presentato come una percentuale. L'identificatore di precisione indica il numero di posizioni decimali desiderato.

R (o r) Riconversione String.Format("{0:r}", 123456.789); 123456,789

L'identificatore di riconversione garantisce che un valore numerico convertito in una stringa venga riportato al medesimo valore numerico. Sebbene sia possibile aggiungere un identificatore di precisione all'identificatore di formato di riconversione, tale identificatore di precisione viene comunque ignorato. Quando si utilizza questo identificatore, infatti, il formato della riconversione ha la precedenza sulla precisione. Questo formato è supportato solo dai tipi a virgola mobile.

X (o x) Esadecimale (Hex) String.Format("{0:x}", 12); String.Format("{0:X}", 12); String.Format("{0:X}", 123456789); c C 75BCD15

Il numero viene convertito in una stringa di cifre esadecimali. L'utilizzo della lettera maiuscola e minuscola nell'identificatore di formato indica se verranno utilizzati caratteri maiuscoli o minuscoli per le cifre esadecimali maggiori di 9.

Stringhe di formato numerico personalizzato

Se gli identificatori di formato numerico standard non forniscono il tipo di formattazione desiderata, sarà possibile utilizzare stringhe di formato personalizzato. Una stringa di formato standard è costituita da un singolo carattere alfabetico, eventualmente seguito da una sequenza di cifre che rappresenta un valore compreso tra 0 e 99. Tutte le altre stringhe di formato corrispondono a stringhe di formato personalizzato.

Carattere di formato Nome Descrizione
0 Segnaposto per zero Se il valore da formattare dispone di una cifra nella posizione in cui nella stringa di formato si trova uno "0", tale cifra verrà copiata nella stringa di risultati. La posizione dell'ultimo "0" a sinistra prima del separatore decimale e dell'ultimo "0" a destra dopo il separatore decimale determina l'intervallo di cifre sempre presenti nella stringa di risultati.
# Segnaposto per cifre Se il valore da formattare dispone di una cifra nella posizione in cui nella stringa di formato si trova uno "#", tale cifra verrà copiata nella stringa di risultati. In caso contrario, nella stringa di risultati non verrà memorizzato alcun valore in tale posizione.
. Separatore decimale Il primo carattere "," della stringa di formato determina la posizione del separatore decimale nel valore formattato. Eventuali ulteriori caratteri "," vengono ignorati.
, Separatore delle migliaia e rappresentazione in scala dei numeri Il carattere "." ha due funzioni. In primo luogo, se la stringa di formato contiene un carattere "." tra due segnaposti per cifre (0 o #) e se a sinistra del separatore decimale ne è presente uno, l'output presenterà separatori delle migliaia inseriti tra ciascun gruppo di tre cifre a sinistra del separatore decimale. In secondo luogo, se la stringa di formato contiene uno o più caratteri "." immediatamente a sinistra del separatore decimale, il numero verrà diviso per 1000 tante volte quanti sono i caratteri "." prima di essere formattato.
% Segnaposto per percentuale La presenza di un carattere "%" in una stringa di formato fa sì che un numero venga moltiplicato per 100 prima di essere formattato. Il simbolo appropriato viene inserito nel numero stesso nella posizione in cui è stato inserito il segno "%" nella stringa di formato.
E0
E+0
E-0
e0
e+0
e-0
Notazione scientifica Se nella stringa di formato è presente una delle stringhe "E", "E+", "E-", "e", "e+" o "e-" immediatamente seguita da almeno un carattere "0", il numero verrà formattato utilizzando la notazione scientifica con una "E" o "e" inserita tra il numero e l'esponente. Il numero dei caratteri "0" che seguono l'indicatore della notazione scientifica determina il numero minimo di cifre da visualizzare nell'output per l'esponente. I formati "E+" ed "e+" indicano che l'esponente deve essere sempre preceduto da un carattere di segno (più o meno). I formati "E", "E-", "e" ed "e-" indicano che solo gli esponenti negativi devono essere preceduti da un carattere di segno.
\ Carattere escape In C# e C++ il carattere barra rovesciata fa sì che il successivo carattere nella stringa di formato venga interpretato come sequenza di escape. Viene utilizzato con sequenze di formattazione tradizionali come "\n" (nuova riga). In alcuni linguaggi è necessario che il carattere di escape stesso sia preceduto da un carattere di escape quando viene utilizzato come un valore letterale. In caso contrario in fase di compilazione il carattere verrà interpretato come una sequenza di escape. Utilizzare la stringa "\\" per visualizzare il carattere "\". Si noti che questo carattere di escape non è supportato in Visual Basic. ControlChars fornisce tuttavia la stessa funzionalità.
'ABC'
"ABC"
Stringa letterale I caratteri racchiusi tra virgolette semplici o doppie vengono copiati nella stringa di risultati in modo letterale e non influiscono sulla formattazione.
; Separatore di sezione Il carattere ";" è utilizzato per separare sezioni di valori positivi, negativi e zero nella stringa di formato.
(altro) Tutti gli altri caratteri Tutti gli altri caratteri vengono copiati nella stringa di risultati come valori letterali nella posizione in cui sono riportati.

Esempi di utilizzo di stringhe di formato numerico personalizzato

Esempio Output
( 12 ).ToString("000"); ( 12 ).ToString("###"); ( 12 ).ToString("0,000.00"); ( 123456.789 ).ToString("0,000.00"); ( 123456.789 ).ToString("0,###,###.00"); 012 12 0.012,00 123.456,79 0.123.456,79
( 123456789 ).ToString("0,,.####"); 12,34568
( 12 ).ToString("#%"); ( 0.5678 ).ToString("#.000%"); ( 0.5678 ).ToString("#.0%"); 1200% 56,780% 56,8%
( 123456789 ).ToString("###e0"); ( 123456789 ).ToString("###E0"); ( 123456789 ).ToString("###E+0"); ( 0.123456789 ).ToString("###E-0"); 123e6 123E6 123E+6 123E-6
( 123 ).ToString("Output is #"); Output is 123
( 12 ).ToString("Positive: 0,000.00;Negative: #"); ( -12 ).ToString("Positive: 0,000.00;Negative: #"); ( -12 ).ToString("Positive: 0,000.00;Negative: -#"); ( -0.1 ).ToString("Positive: 0,000.00;Negative: -#;Zero!"); Positive: 0.012,00 Negative: 12 Negative: -12 Zero!

Formattazione di data e ora

La formattazione di un tipo DateTime può essere in forma standard (mediante l'applicazione di uno stile predefinito) o custom (mediante un formato specificato dall'utente)

La data di riferimento (dt) utilizzata negli esempi seguenti corrisponde al 25 Aprile 2007 alle ore 14, 37 minuti, 54 secondi e 309 millesimi ed è definita come:

DateTime dt = new DateTime(2007, 4, 25, 14, 37, 54, 309);

Stringhe di formato DateTime standard

La formattazione standard prevede un singolo carattere tra quelli inclusi nella tabella riportata di seguito. Se l'identificatore di formato non è contenuto nella tabella che segue, verrà generata un'eccezione in fase di esecuzione. Se la stringa di formato è più lunga di un singolo carattere, verrà interpretata come una stringa di formato personalizzato, anche se i caratteri aggiuntivi sono costituiti da spazi.

Formato Nome Esempio Output
d Data breve dt.ToString("d"); 25/04/2007
D Data estesa dt.ToString("D"); mercoledì 25 aprile 2007
t Ora breve dt.ToString("t"); 14.37
T Ora estesa dt.ToString("T"); 14.37.54
f Data e ora completa (ora breve) dt.ToString("f"); mercoledì 25 aprile 2007 14.37
F Data e ora completa (ora estesa) dt.ToString("f"); mercoledì 25 aprile 2007 14.37.54
g Generale (ora breve) dt.ToString("g"); 25/04/2007 14.37
G Generale (ora estesa) dt.ToString("G"); 25/04/2007 14.37.54
M (o m) Mese e giorno dt.ToString("m"); 25 aprile
R (o r) RFC 1123 dt.ToString("r"); Wed, 25 Apr 2007 14:37:54 GMT
s ISO 8601 dt.ToString("s"); 2007-04-25T14:37:54
u Universale dt.ToString("u"); 2007-04-25 14:37:54Z

In occasione della formattazione della data e dell'ora non viene eseguita alcuna conversione di fuso orario. La conversione della data e dell'ora locali in tempo universale deve quindi essere eseguita prima di utilizzare questo identificatore di formato.

U Universale dt.ToString("U"); mercoledì 25 aprile 2007 12.37.54

L'ora visualizzata è quella standard, non quella locale, ed equivale al valore DateTime.

Y (o y) Anno (year) e mese dt.ToString("y"); aprile 2007

Stringhe di formato DateTime personalizzato

È possibile esercitare un maggiore controllo sulla formattazione di un oggetto DateTime utilizzando identificatori di formato personalizzati (vedi tabella seguente)

Formato Descrizione Esempio Output
d Giorno del mese (1 cifra) dt.ToString("%d"); ( new DateTime(2007, 4, 3) ).ToString("%d"); 25 3
dd Giorno del mese (2 cifre) dt.ToString("dd"); ( new DateTime(2007, 4, 3) ).ToString("dd"); 25 03
ddd Giorno della settimana (abbreviato) dt.ToString("ddd"); mer
dddd Giorno della settimana (esteso) dt.ToString("dddd"); mercoledì
f Frazione di secondo (1 cifra, zeri visualizzati) dt.ToString("%f"); 3
ff Frazione di secondo (2 cifre, zeri visualizzati) dt.ToString("ff"); 30
fff Frazione di secondo (3 cifre, zeri visualizzati) dt.ToString("fff"); 309
ffff Frazione di secondo (4 cifre, zeri visualizzati) dt.ToString("ffff"); 3090
fffff Frazione di secondo (5 cifre, zeri visualizzati) dt.ToString("fffff"); 30900
ffffff Frazione di secondo (6 cifre, zeri visualizzati) dt.ToString("ffffff"); 309000
fffffff Frazione di secondo (7 cifre, zeri visualizzati) dt.ToString("fffffff"); 3090000
F Frazione di secondo (1 cifra, zeri omessi) dt.ToString("%F"); 3
FF Frazione di secondo (2 cifre, zeri omessi) dt.ToString("FF"); 3
FFF Frazione di secondo (3 cifre, zeri omessi) dt.ToString("FFF"); 309
FFFF Frazione di secondo (4 cifre, zeri omessi) dt.ToString("FFFF"); 309
FFFFF Frazione di secondo (5 cifre, zeri omessi) dt.ToString("FFFFF"); 309
FFFFFF Frazione di secondo (6 cifre, zeri omessi) dt.ToString("FFFFFF"); 309
FFFFFFF Frazione di secondo (7 cifre, zeri omessi) dt.ToString("FFFFFFF"); 309
g (o gg) Era (a.C. / d.C.) dt.ToString("%g"); dt.ToString("gg"); d.C. d.C.
h Ora (1 cifra, 1-12) dt.ToString("%h"); 2
hh Ora (2 cifre, 1-12) dt.ToString("hh"); 02
H Ora (1 cifra, 0-23) dt.ToString("%H"); ( new DateTime(2007, 4, 25, 9, 5, 7) ).ToString("%H"); 14 9
HH Ora (2 cifre, 0-23) dt.ToString("HH"); ( new DateTime(2007, 4, 25, 9, 5, 7) ).ToString("HH"); 14 09
m Minuti (1 cifra) dt.ToString("%m"); ( new DateTime(2007, 4, 25, 9, 5, 7) ).ToString("%m"); 37 5
mm Minuti (2 cifre) dt.ToString("mm"); ( new DateTime(2007, 4, 25, 9, 5, 7) ).ToString("mm"); 37 05
M Mese (1 cifra) dt.ToString("%M"); 4
MM Mese (2 cifre) dt.ToString("MM"); 04
MMM Mese (abbreviato) dt.ToString("MMM"); apr
MMMM Mese (esteso) dt.ToString("MMMM"); aprile
s Secondi (1 cifra) dt.ToString("%s"); ( new DateTime(2007, 4, 25, 9, 5, 7) ).ToString("%s"); 54 7
ss Secondi (2 cifre) dt.ToString("ss"); ( new DateTime(2007, 4, 25, 9, 5, 7) ).ToString("ss"); 54 07
t Indicatore AM / PM (primo carattere) DateTimeFormatInfo fi = new DateTimeFormatInfo();
fi.AMDesignator = "Mattina";
fi.PMDesignator = "Pomeriggio";
dt.ToString("%t");
P

Le impostazioni di default della cultura italiana non prevedono nessun simbolo di identificazione per AM e PM. Nell'esempio è stato dunque utilizzato un DateTimeFormatInfo per forzare la visualizzazione di questo formato.

tt Indicatore AM / PM (completo) DateTimeFormatInfo fi = new DateTimeFormatInfo();
fi.AMDesignator = "Mattina";
fi.PMDesignator = "Pomeriggio";
dt.ToString("tt");
Pomeriggio

Le impostazioni di default della cultura italiana non prevedono nessun simbolo di identificazione per AM e PM. Nell'esempio è stato dunque utilizzato un DateTimeFormatInfo per forzare la visualizzazione di questo formato.

y Anno (1 cifra) dt.ToString("%y"); 7
yy Anno (2 cifre) dt.ToString("yy"); 07
yyyy Anno (4 cifre) dt.ToString("yyyy"); 2007
z Ore di fuso orario (1 cifra) dt.ToString("%z"); +2
zz Ore di fuso orario (2 cifre) dt.ToString("zz"); +02
zzz Ore e minuti di fuso orario dt.ToString("zzz"); +02:00
: Separatore dell'ora dt.ToString("%:"); .
/ Separatore della data dt.ToString("%/"); /
"ABC" (oppure 'ABC') Valore letterale dt.ToString("'d'"); d

Si noti che nell'utilizzo dei caratteri di formato personalizzati costituiti da un solo carattere risulta necessario anteporre il carattere % per distinguerli dagli identificatori di formato standard (se disponibili come ad esempio per "d", "f", "F" o "g"; se al singolo carattere non corrisponde un formato standard e si omette il carattere "%" viene generata un'eccezione di tipo FormatException)

Combinando uno o più identificatori di formato personalizzati si può costruire uno schema di formattazione in grado di restituire l'output desiderato:

Esempio Output
dt.ToString("'Ora corrente:' HH:mm:ss"); Ora corrente: 14.37.54
dt.ToString("dddd d MMMM yyyy - HH:mm:ss (z)"); mercoledì 25 aprile 2007 - 14.37.54 (+2)

Formattazione di enumeratori

È possibile utilizzare il metodo ToString per creare un nuovo oggetto stringa che rappresenti il valore numerico, esadecimale o stringa di un Enum utilizzando le stringe di formattazione disponibili (vedi tabella seguente):

L'enumeratore di riferimento (Colors) utilizzato negli esempi seguenti è definito come:

public enum Colors
{
    Default = 0,
    White = 1,
    Blue = 2,
    Red = 3,
    Black = 4
}
Formato Nome Esempio Output
G (o g) Generale Colors.Red.ToString("g"); Red

Visualizza la voce di enumerazione sotto forma di valore di stringa, se possibile. In caso contrario, visualizza il valore integer dell'istanza corrente. Se l'enumerazione viene definita con l'attributo Flags impostato, i valori di stringa di ciascuna voce valida saranno concatenati tra loro, separati da virgole. Se l'attributo Flags non è impostato, un valore non valido verrà visualizzato sotto forma di voce numerica.

F (o f) Stringa Colors.Red.ToString("f"); Red
D (o d) Intero Colors.Red.ToString("d"); 3
X (o x) Esadecimale (8 cifre) Colors.Red.ToString("x"); 00000003