C#

I CARATTERI

Anche i caratteri hanno la loro brava struttura che si preoccupa di rappresentarli. Si tratta di System.Char che ha il suo alias in char. La definizione che si trova su MSDN è chiara: rappresenta un carattere come unità di codice UTF 16 in un range che va da U+0000 a U+ffff. (ovvero da 0 a 65535). Esso pertanto viene gestito attraverso due byte. Il carattere vuoto è il default per questo tipo. Esistono vari sistemi per inizializzare una variabile di tipo char:

char c1 = ‘a’; \\ modo più consueto
char c2 = (char)97; \\ tramite cast, vedremo di che si tratta
char c3 = ‘\x0061’; \\ esadecimale
char c4 = ‘\u0061’; \\ Unicode


Un carattere è, come appare in particolare dal primo esempio, circondato da un coppia di singoli apici; usare i doppi apici definirebbe una stringa ed è un altro pianeta.
La struttura che definisce i caratteri ha molti metodi ma solo due proprietà: MaxValue e Minvalue, statiche, che vediamo all'opera nel seguente frammento di esempio a riprova dei valori precedentemente indicati:

Console.WriteLine((int)(char.MinValue));
Console.WriteLine((int)(char.MaxValue));

Queste due righe ci restituiscono i valori 0 e 65535. In questo senso è evidente la stretta correlazione tra numeri e caratteri.
Se le proprietà sono due sole i metodi invece sono tanti e molto comodi; a parte i soliti ereditati da Object vediamone alcuni tra i più interessanti (secondo me), tenendo presente che, per forza di cose, offrirò una panoramica molto generica, eventuali approfondimenti sono disponibili sul sito MSDN:


Identificativo metodo Descrizione e uso
CompareTo Effettua il confronto tra due char
char1.CompareTo(char2)
Restituisce -1 se char2 è maggiore di char1, 0 in caso di uguaglianza, 1 se char1 è maggiore di char2. Internamente è definito come segue:
public int CompareTo(
char value
)


ConvertFromUtf32 Converte un carattere codificato UTF32 ad una stringa UTF16
stringa = Char.ConvertFromUtf32(intero)
Si tratta di un metodo statico come traspare dalla sua definizione
public static string ConvertFromUtf32(
int utf32
)


ConvertToUtf32 Opposto al metodo precedente, restituisce un intero. Esempio
using System;
class Program
{
  public static void Main()
  {
    int x = 0;
    string s1 = "pp";
    x = char.ConvertToUtf32(s1, 0);
    Console.WriteLine(x);
  }
}

mentre formalmente si ha:
public static int ConvertToUtf32(string s,int index)

esiste comunque la seguente alternativa:

public static int ConvertToUtf32(
char highSurrogate,
char lowSurrogate
)

dove i range accettabili per i due parametri sono rispettivamente:
U+D800 fino a U+DBFF
U+DC00 fino a U+DFFF


Equals Stabilisce se due caratteri sono uguali restituendo true o false.
public bool Equals(
char obj)

fr
ammento esempio:
Console.WriteLine('a'.Equals('b'))


GetNumericValue Restituisce un float partendo da un carattere.
public static double GetNumericValue(char c )
Esempio
char a = '3';
Console.WriteLine(char.GetNumericValue(a));

Il carattere deve essere la rappresentazione di un numero diversamente il risultato sarà -1.
Esiste anche una seconda forma:
public static double GetNumericValue(string s,int index )
Questa restituisce il valore del carattere posizionato all'indice index nella stringa s, se questo è numerico, altrimenti abbiamo come risultato -1, proprio come appena visto. Il primo indice della stringa è 0.
string s = "ab3cd";
Console.WriteLine(char.GetNumericValue(s, 2));


Parse Effettua il parsing di una stringa convertendola nel carattere corrispondente. La stringa deve essere costituita da un solo elemento altrimenti si ha un'eccezione, così come accade se il dato passato al metodo non è un numero. La forma è:
public static char Parse(string s)
Esempio:
char a = char.Parse("A");
Console.WriteLine(a);


ToLower, ToUpper Restituiscono il carattere rispettivamente in minuscolo o maiuscolo trasformandolo se è nel formato opposto mentre nulla accade se si trova già come destinato.
public static char ToLower(char c)
public static char ToUpper(char c)


TryParse public static bool TryParse(string s,out char result)
Anche questa istruzione effettua un parsing ma in caso di errore viene restituito false invece di una eccezione. In caso di successo abbiamo true. A mio avviso approcciare il problema del passaggio da carattere a numero con questo metodo è preferibile spesso rispetto a Parse. Ecco un esempio completo:
using System;
class Program
{
  public static void Main()
  {
    string s1 = "a";
    char c1;
    bool b1;
    b1 = char.TryParse(s1, out c1);
    Console.WriteLine(b1);
    Console.WriteLine(c1);
  }
}



Esiste poi una lunga serie di metodi che ci aiuta a esporre la natura del carattere; questi metodi hanno un nome "parlante" e li propongo in ordine alfabetico;

IsControl, IsDigit, IsHighSurrogate, IsLetter, IsLetterOrDigit, IsLower, IsLowerSurrogate, IsNumber, IsPunctuation, IsSeparator, IsSurrogate, IsSurrogatePair, IsSymbol, IsUpper, IsWhiteSpace.

Alcuni sono evidenti altri un po' più complicati e il loro uso può essere approfondito come sempre sul sito MSDN. Di seguito fornisco un esempio di base:

  Esempio 6.1
1
2
3
4
5
6
7
8
9
10
11
12
using System;
class Program
{
  public static void Main()
  {
    char c1 = '1';
    char c2 = 'b';
    Console.WriteLine(char.IsLetter(c1));
    Console.WriteLine(char.IsDigit(c2));
    Console.WriteLine(char.IsLetterOrDigit(c2));
  }
}

Dei caratteri fanno sostanzialmente parte anche le sequenze di escape anche se la loro rappresentazione differisce leggermente da quanto siamo abituati ad immaginarcela quando parliamo di caratteri in quanto, in effetti, sono rappresentabili tramite una coppia i simboli:

Sequenza Uso
\' apice
\" doppio apice
\\ backslash
\0 null
\a alert
\b spazio indietro
\f form feed
\n a capo
\r ritorno carrello
\t tabulazione orizzontale
\v tabulazione verticale

Anche qui l'uso è banalissimo, come vediamo in questo semplice contatore:

  Esempio 6.2
1
2
3
4
5
6
7
8
9
10
11
12
using System;
class Program
{
  public static void Main()
  {
    for (int i = 0; i < 100000; i++)
    {
      Console.Write(i);
      Console.Write('\r');
    }
  }
}

Ancora a testimonianza della vicinanza tra caratteri e numeri, il tipo char può essere implicitamente convertito in un valore numerico come mostra il seguente spezzone che potrete provare a compilare senza riscontrare alcun problema:

char c = 'a';
int x = 5;
int y = x + c;
Console.WriteLine(y);


esso ci restituisce come risultato il numero 102, ovvero 97 + 5, laddove 97 è il codice ASCII della lettera 'a'. La conversione implicita ha successo in questi casi:

da char a ushort , int, uint, long, ulong, float, double, or decimal

altrimenti è prevista una conversione esplicita.

E' possibile anche passare da vari formati a carattere attrraverso la classe Convert, di cui parleremo ancora in altri ambiti o, come abbiamo già visto ad inizio capitolo, attraverso un cast. Ad esempio:

char c1 = (char)98; // cast
char c2 = Convert.ToChar(99); // uso Convert


come sempre bisogna valutare i valori che si intendono convertire per non avere sorprese.

Prima di chiudere ecco come il seguente codice:

using System;
class Program
{
  public static void Main()
  {
    char a = 'a';
  }
}

viene tradotto in IL:

.method public hidebysig static void Main() cil managed
{
.entrypoint
// Code size 5 (0x5)
.maxstack 1
.locals init (char V_0)
IL_0000: nop
IL_0001: ldc.i4.s 97
IL_0003: stloc.0
IL_0004: ret
} // end of method Program::Main


L'istruzione in rosso carica il valore costante 97 che corrisponde al carattere 'a'

Il tipo char è a volte un po' dimenticato in tanti testi ma è in realtà molto utile per tante applicazioni. Riparleremo dei caratteri quando incontreremo le stringhe.