I. iruri de caractere Clasa string (alias C# pentru System.String) reprezint un ir de caractere a crui valoare, odat stabilit, nu mai poate fi modificat (iruri imutabile). De fapt, metodele care modific un obiect ir de caractere returneaz un nou obiect ir de caractere. Pentru operaiile uzuale cu iruri de caractere (comparri, inserri, cutri, nlocuiri, adugri, conversii, formatri...) .NET Framework pune la dispoziie i alte clase, precum StringBuilder, StringFormat i StringCollection. Se consider un prim exemplu: using System; namespace pnoro{ class Aplicatie{ public static void Main(string[] args){ //un sir nul string s1 = null; //un sir initializat //sunt doua siruri identice "egale"? string s2="astra 19E"; string s3="astra 19E"; if (s2 == s3) Console.WriteLine("egale prin =="); else Console.WriteLine("diferite prin =="); if (s2.Equals(s3)) Console.WriteLine("egale prin Equals"); else Console.WriteLine("diferite prin Equals"); Console.WriteLine((object)s2 == (object)s3); //True //cele doua siruri sunt literali //ce se intampla daca avem o variabila sir? string s33 = string.Copy(s2); Console.WriteLine((object)s2 == (object)s33); //False //inlocuirea unui caracter string s4 = "Am un receiver strong 6155."; string s5 = s4.Replace('s','S'); Console.WriteLine(s3);
//inserarea unui subsir s1="drbox"; s1=s1.Insert(2, "eam"); Console.WriteLine(s1); //obiectele string se pot manipula ca tablouri de caractere s1 += " 500s"; for (int i=0; i<s1.Length; ++i) Console.Write("{0, -2}", s1[i]); Console.WriteLine(); //se poate concatena un string cu orice alt tip, utilizand + string s6 = s1 + " costa " + 200 + " euro"; Console.WriteLine(s6); Console.ReadLine(); } }; } 2 Deoarece irurile de caractere sunt imutabile, sistemul pstreaz irurile ntr-o locaie comun i elimin duplicatele. Din acest motiv, atunci cnd compar dou obiecte string iniializate pe baza aceluiai literal, operatorul == returneaz true, n contradicie cu comportamentul su uzual. Se mai observ c s2 i s3 sunt referine ctre aceeai zon de memorie, dovad a faptului c se elimin duplicatele. Doar la crearea explicit a unei variabile ir se obine un nou obiect string! Metodele String.Format i Console.WriteLine sunt guvernate de aceleai reguli de formatare. Specificaiile de format sunt date sub forma {N [,M][:sir]}, unde: N este indexul (ncepnd de la 0) argumentului ce trebuie formatat; M indic limea regiunii ce va conine valoarea formatat, implicit aliniat la dreapta; dac M este negativ, alinierea se face la stnga; sir este o secven de coduri de formatare; dac lipsete, formatarea este realizat de ctre metoda ToString a obiectului cruia i se aplic specificaia de format curent. Astfel, urmtoarele instruciuni afieaz acelai rezultat: Console.WriteLine(100); Console.WriteLine("{0}", 100); Console.WriteLine("{0:D3}", 100); Console.WriteLine(string.Format("100")); Console.WriteLine(string.Format("{0}",100)); Console.WriteLine(string.Format("{0:D3}",100));
Codurile (numerice) de formatare iau forma Xn, unde n este precizia (numrul de zerouri/cifre semnificative de la dreapta punctului zecimal) iar X unul dintre caracterele de format din urmtorul tabel: Caracter de format Interpretare C, c Moned (currency). D, d ntreg zecimal. E, e Exponent. F, f Reprezentare n virgul fix. G, g General; 15 cifre pentru double i 7 cifre pentru float. N, n Numr; similar cu F, adugndu-se , pentru a separa miile. P, p Procent. R, r Rotunjire pentru reprezentrile n virgul mobil; garanteaz faptul c un numr convertit ntr-un ir va fi parsat napoi n exact acelai numr. Se testeaz dac, utiliznd G, valoarea este parsat napoi; n caz de insucces, valoarea este formatat cu 17/9 cifre. Dac este prezent, precizia este ignorat. X, x Hexazecimal. 3 Dac specificaiile standard de format nu sunt suficiente, se pot construi propriile specificaii utiliznd marcatori pentru a preciza numrul minim i maxim de cifre utilizate, locul i apariia semnului negativ precum i apariia unui text n interiorul numrului: Marcator Scop Descriere 0 Afieaz 0 Afieaz zerouri nesemnificative dac reprezentarea are mai puine cifre dect numrul zerourilor din format. # Afieaz cifr nlocuiete cu cifrele semnificative. . Punct zecimal Afieaz punctul zecimal. , Separator de grup Separ miile. % Procent Afieaz semnul procentual. E+0, e+0 Notaie eponenial E-0, e-0 Notaie eponenial \ Literal caracter Utilizat n secvenele tradiionale de formatere precum \n. ABC Literal ir de caractere Afieaz un ir. ABC Literal ir de caractere Afieaz un ir. ; Separator de seciune Specific output diferit dac valoarea numeric este negativ, 0 sau pozitiv.
double j = 1234.345678; //afiseaza partea intreaga (cifrele semnificative) Console.WriteLine("{0:#}", j); //afiseaza numarul, cu 3 zecimale Console.WriteLine("{0:.000}", j); //afiseaza numarul, cu 2 zecimale Console.WriteLine("{0:0000.00}", j); //afiseza un 0 nesemnificativ, separatorul de mii si 3 zecimale Console.WriteLine("{0:00,000.000}", j); j = -1234.345678; //afisaj alternativ pozitiv/negativ Console.WriteLine("{0:00,000.000;minus 00,000.0}", j); j=0; //afisaj alternativ pozitiv/negativ/0 Console.WriteLine("{0:00,000.000;minus 00,000.0;ZERO}", j);
Executnd acest fragment de program, se obine: 1234 1234.346 1234.35 01,234.346 minus 01,234.3 ZERO Se remarc rotunjirea efectuat atunci cnd s-au afiat doar dou zecimale! 4 Pentru tipurile numerice, metoda ToString produce o reprezentare ir de caractere a unui numr; complementara ei este metoda Parse. int k = int.Parse("12345"); double dd = double.Parse(" -1,234.5678 "); Console.WriteLine("k={0} dd={1}", k, dd);
Atunci cnd se dorete ca s se efectueze un set de modificri asupra unui acelai ir, se utilizeaz System.Text.StringBuilder: using System; using System.Text; namespace pnoro{
class Aplicatie{ public static void Main(string[] args){ StringBuilder sb = new StringBuilder("dream"); sb.Replace('d','D'); sb.Insert(sb.Length, "Box 500s "); sb.Append(" is running Linux!"); string s = sb.ToString(); Console.WriteLine(s); //un tablou de caractere utilizate ca separatori de cuvinte char[] separatori = new Char[]{' '}; //separarea unui sir in cuvinte cu Split foreach (string ss in s.Split(separatori)) Console.WriteLine(ss); Console.ReadLine(); } }; }
Executnd acest program, se observ un neajuns n utilizarea metodei Split: deoarece ntre 500s i is sunt dou spaii, apare un rnd liber. Acest neajuns poate fi eliminat prin utilizarea expresiilor regulate.
II. Expresii regulate Expresiile regulate ofer o modalitate flexibil, puternic i eficient de a procesa textul. Limbajul expresiilor regulate din C#, proiectat compatibil cu cel din Perl 5, include caractere literal (normale) i metacaractere; cele mai utilizate metacaractere i semnificaiile lor sunt prezentate n urmtorul tabel: Metacaracter Semnificaie . Orice caracter, cu excepia lui \n. [list] Un singur caracter din list. [^list] Un singur caracter, care nu este n list. [char 1 -char 2 ] Un singur caracter, din intervalul specificat. \w Caracter liter sau cifr: [a-zA-Z0-9] \W Caracter care nu este liter sau cifr. 5 \s Caracter spaiu: [ \n\r\t\f] \S Caracter care nu este spaiu. \d Caracter cifr: [0-9] \D Caracter care nu este cifr ^ nceputul unei linii de text. $ Sfritul unei linii de text. \b n limita unui cuvnt. \B n afara limitei unui cuvnt. * 0 sau mai multe potriviri. + 1 sau mai multe potriviri. ? 0 sau 1 potriviri. {n} Exact n potriviri. {n,} Cel puin n potriviri. {n,m} Cel puin n potriviri, dar nu mai mult de m potriviri. () Captureaz subirul ce se potrivete, sub forma unui grup. (?<nume>) Captureaz subirul ce se potrivete, sub forma unui grup cu nume. | Operaia SAU logic.
Observaii: Atunci cnd un literal ir de caractere conine metacaractere de forma \c, deoarece acestea nu sunt secvene escape, literalii trebuie prefixai cu caracterul @. Pentru a afia \c se utilizeaz \\c.
Expresiile regulate sunt implementate n clasa Regex din spaiul de nume System.Text.RegularExpression; obiectele Regex sunt i ele imutabile. Pentru a separa n cuvinte un ir de caractere, se apeleaz metoda Regex.Split; de data aceasta, lista separatorilor se transmite direct constructorului clasei Regex, sub forma unei expresii regulate: using System; using System.Text.RegularExpressions;
namespace pnoro{
class Aplicatie{ public static void Main(){ string s = "Dreambox 500s is running Linux!"; //acceasi problema: despartirea intre 2 spatii consecutive Regex er1 = new Regex(" "); foreach (string cuvant in er1.Split(s)) Console.WriteLine(cuvant); //utilizam o alta expresie regulata: [ ]+ Regex er2 = new Regex("[ ]+"); foreach (string cuvant in er2.Split(s)) Console.WriteLine(cuvant); 6 //se generalizeaza pentru orice caracter spatiu: [\s]+ Regex er3 = new Regex(@"[\s]+"); foreach (string cuvant in er3.Split(s)) Console.WriteLine(cuvant); Console.ReadLine(); } }; }
Se observ c Regex.Split elimin caracterele spaiu; ce se ntmpl dac asupra irului de caractere trebuie s operm doar nite modificri i trebuie s pstrm delimitatorii pentru alte procesri? Se utilizeaz (), care captureaz/pstreaz un subir sub forma unui grup: using System; using System.Text.RegularExpressions;
namespace pnoro{ class Aplicatie{ public static void Main(){ //un singur spatiu intre 500s si is string s = "Dreambox 500s is running Linux!"; //pastreaza spatiul Regex er1 = new Regex("( )"); foreach(string cuvant in er1.Split(s)) Console.WriteLine(cuvant); //pasteaza orice caracter spatiu Regex er2 = new Regex(@"(\s)"); foreach(string cuvant in er2.Split(s)) Console.WriteLine(cuvant); Console.ReadLine(); } }; }
Un obiect Match reprezint rezultatul unei operaii de cutare/potrivire a unui ablon descris de o expresie regulat. Un obiect Match este imutabil, iar clasa Match nu posed nici un constructor public; din acest motiv, un obiect Match se poate obine doar apelnd metoda Regex.Match. Clasa Match pstreaz i ofer acces la subirurile extrase n procesul de cutare, la irul n care se caut i la expresia regulat n uz, fcnd astfel posibil renceperea cutrii din punctul n care cutarea anterioar s-a oprit (n cazul n care ablonul este prezent de mai multe ori n irul n care se caut) prin intermediul metodei Match.NextMatch. Acest proces poate fi descris mai simplu utiliznd clasa MatchCollection, ale crei instane sunt returnate de Regex.Matches: 7 using System; using System.Text.RegularExpressions;
namespace pnoro{
class Aplicatie{ public static void Main(){ //un singur spatiu intre 500s si is string s = "Dreambox 500s is running Linux!"; //cauta prima aparitie a lui 'in' Regex er = new Regex("in"); Match m1 = er.Match(s); if (m1.Success) Console.WriteLine("Am gasit \'{0}\' la pozitia {1}.",m1.Value, m1.Index); //cauta toate apairiile lui 'in' Match m2; for(m2=er.Match(s);m2.Success;m2=m2.NextMatch()) Console.WriteLine("Am gasit \'{0}\' la pozitia {1}.", m2.Value, m2.Index); //cauta toate aparitiile lui 'in' utilizand MatchCollection MatchCollection mc = er.Matches(s); foreach (Match m in mc) Console.WriteLine("Am gasit \'{0}\' la pozitia {1}", m.Value, m.Index); Console.ReadLine(); } }; }
O expresie regulat poate fi descompus n mai multe grupuri; de exemplu, ablonul (i(n))g conine grupurile n, in i ing. Un astfel de grup este descris de ctre clasa Group. Clasa Match pune la dispoziie proprietatea Groups, care returneaz un obiect GroupCollection, prin intermediul cruia pot fi accesate grupurile individuale: using System; using System.Text.RegularExpressions; namespace pnoro{ class Aplicatie{ public static void Main(){ string s1 = "Dreambox 500s is running Linux!"; //cauta prima aparitie a lui 'ing' //grupurile n in si ing Regex er1 = new Regex("(i(n))g"); Match m1 = er1.Match(s1); GroupCollection gc = m1.Groups; foreach(Group g in gc) Console.WriteLine("Am gasit \'{0}\' la pozitia {1}", g.Value, g.Index); string s2 = "Dreambox:Linux"; //grupuri cu nume //primul grup se numeste 'NUME', al doilea grup se numeste 'SO' Regex er2 = new Regex("(?<NUME>\\w+):(?<SO>\\w+)"); Match m2 = er2.Match(s2); //colectia de grupuri este indexata //index sir de caractere Console.WriteLine("{0} <-> {1}", m2.Groups["NUME"].Value, m2.Groups["SO"].Value); Console.ReadLine(); } }; } 8 Proprietatea Group.Captures returneaz un obiect CaptureCollection; explicit, se poate scrie astfel: using System; using System.Text.RegularExpressions; namespace pnoro{ class Aplicatie{ public static void Main(){ string s = "Dreambox 500s is running Linux ing!"; //cauta prima aparitie a lui 'ing' Regex er = new Regex("(i(n))g"); Match m = er.Match(s); GroupCollection gc = m.Groups; //parcurge colectia de grupuri foreach(Group g in gc) Console.WriteLine("Am gasit \'{0}\' la pozitia {1}", g.Value, g.Index); //alternativ //parcurge colectia de grupuri foreach (Group g in gc){ //parcurge colecia de capturi CaptureCollection cc = g.Captures; foreach (Capture c in cc) Console.WriteLine("Am gasit \'{0}\' la pozitia {1}", c.Value, c.Index); } Console.ReadLine(); } }; } Regex.Replace este o metod ce poate fi utilizat pentru tergerea spaiilor, desprirea n cuvinte, tergerea sau nlocuirea unor subiruri; de exemplu: using System; using System.Text.RegularExpressions; namespace pnoro{ class Aplicatie{ public static void Main(){ string s = " spatii sterse"; Regex er1 = new Regex(@"^\s*"); Console.WriteLine(er1.Replace(s, "")); Console.ReadLine(); } } }
Observaie: Clase Regex pune la dispoziie i variantele statice ale metodelor Split, Replace i Match; acestea pot fi folosite fr a iniializa obiecte Regex.
Exist i o versiune suprancarcat a constructorului clasei Regex care accept un al doilea argument, de tipul RegexOptions; printre valorile acestui tip enumerare se regsesc IgnoreCase i RightToLeft.