Кратко съдържание



страница64/73
Дата21.07.2018
Размер9.03 Mb.
#76887
1   ...   60   61   62   63   64   65   66   67   ...   73

Класът StringInfo


Както споменахме при разглеждането на стандарта Unicode, някои сим­воли се представят с повече от една 16-битова стойност. Тъй като един Char обект съдържа информация за една 16-битова стойност, няма как той да съхрани графеми, съставени от повече от една Unicode стойност.

Ако един низов обект, съдържащ съставни графеми, се обхожда символ по символ, то една графема, която се състои от няколко, примерно три, абстрактни Unicode стойности, няма да бъде коректно разпозната. Тъй като тези стойности са записани в последователни Char обекти, индекса­торът на класа String ще разгледа всяка съставна стойност като отделен символ.

Съставните символи могат да бъдат съхранявани в низ, като класът StringInfo дава възможност низовете да се обхождат графема по графе­ма. Чрез метода GetTextElementEnumerator() можем да получим итера­тор по отделните графеми на низа. След това с методите MoveNext() и GetTextElement() можем да осъществяваме достъп до поредната графема.

Използване на StringInfo – пример


Следващият пример илюстрира обхождането на отделните графеми от даден Unicode текст:

String s = "s\u0069\u0307\u0301\u0078\u0323";

TextElementEnumerator graphemes =

StringInfo.GetTextElementEnumerator(s);

StringBuilder text = new StringBuilder();

while (graphemes.MoveNext())

{

string grapheme = graphemes.GetTextElement();



foreach (char ch in grapheme)

{

text.AppendFormat("\\u{0:X4}", (int) ch);



}

text.Append(" = " + grapheme);

text.Append(Environment.NewLine);

}

MessageBox.Show(text.ToString(), s);



Резултатът от изпълнението на примера е низ от три символа в заглавието на показа­ната диалогова кутия и всяка от получените графеми, предста­вена със съответните Unicode стойности, от които се състои.

Друг начин за ползване на класа StringInfo е чрез неговия метод ParseCombiningCharacters(…). Той приема като параметър String обект и връща масив от цели числа, които съдържат началните индекси на отдел­ните единични или съставни символи.


Интерниране на низове


При работа със string обекти често се налага да се извърши сравняване на два низа. Тази операция отнема много системни ресурси и ако нашето приложение предполага много такива операции, то това ще влоши бързо­действието на програмата ни.

С цел спестяване на памет CLR поддържа хеш таблица на всички изпол­звани низови константи чрез структурата от данни "intern pool". Всеки символен низ, които се намира в "intern pool", се нарича интерниран.

В тази таблица се записват всички заложени в сорс кода символни низове, като е предвиден и методът System.Intern(String) за добавяне на дина­мично генерираните символни низове.

При добавянето на нов запис в таблицата първо се проверява дали символният низ не съвпада с вече въведен такъв. Така еднаквите низове се съхраняват в паметта физически на едно място. Сравнението на два интернирани низа става много по-бързо, защото те не се сравняват по съставящите ги символи, а се извършва директно сравнение на референ­циите им.

Методът System.Intern() позволява на програмиста сам да интернира динамично генериран низ по време на изпълнение на програмата, ако той не съществува в таблицата, и връща референция към него.

Методът String.IsInterned() проверява дали даден низ съществува в хеш таблицата и връща референция към него, ако вече е добавен. В противен случай връща null.

Всички символни низове, заложени като константи в сорс кода, винаги се добавят в хеш таблицата "intern pool", но това не важи за низовете, дефи­нирани по време на изпълнение. Нека разгледаме следния пример:

string s1 = "Няма бира!";

string s2 = "Няма ";

s2 = s2 + "бира!";

Console.WriteLine(Object.ReferenceEquals(s1,s2)); // False

s2 = String.Intern(s2);

Console.WriteLine(Object.ReferenceEquals(s1, s2)); // True



На първия ред дефинираме String обект, като стойността му ще се запише в хеш таблицата на "intern pool", когато то се компилира от JIT компилатора.

Тъй като s2 е дефиниран динамично, стойността му не се записва в "intern pool" и методът Object.ReferenceEquals(s1, s2) ще върне false.

За да интернираме s2, използваме статичния метод String.Intern(), който приема като параметър низ и търси в хеш таблицата "intern pool". Ако подаденият низ бъде намерен, методът връща референция към вече съществуващото поле.

Форматиращи низове


Възможностите на .NET Framework за форматиране ни позволяват да пре­образуваме обект в низ, който е подходящ за извеждане на екрана. С форматиращи низове лесно може да представим информацията, предназ­начена за потребителя, в четим и разбираем вид.

Следните методи използват форматиращи низове:



  • IFormattable.ToString(string format)

  • String.Format(string format, …)

  • Console.WriteLine(…)

  • StringBuffer.AppendFormat(…)

Използване на форматиращи символи


Форматирането се задава с форматиращи символи и комбинации от тях. Ето няколко примера:

string s = 42.ToString("C5"); // s = "00042"

string s = String.Format("{0:P2}", 0.374); // s = "37,4%"

Console.WriteLine("Приходите за {0:d.MM.yyyy г.} са " +

"{1:C2}", DateTime.Now, 1872.43);

// Result: Приходите за 4.08.2004 г. са 1 872,43 лв


Методите, които приемат съставен форматиращ низ (composite formatting string) и променлив брой аргументи, изискват параметрите да се номе­ри­рат и поставят във фигурни скоби, съдържащи незадължителен формати­ращ низ. Ето пример:

Console.WriteLine("Здравейте, {0}!\n" +

"Днес е {1:dd.MM.yyyy, а часът е HH:mm:ss}.\n" +

"Вие сте посетител номер {2:D6}.\nДължите {3:C2}.",

"Бай Иван", DateTime.Now, 38, 17.40);

// Result:

// Здравейте, Бай Иван!

// Днес е 04.08.2004, а часът е 19:01:09.

// Вие сте посетител номер 000038.

// Дължите 17,40 лв.


В примера методът Console.WriteLine(…) се извиква с форматиращ низ и 4 параметъра, които се използват при форматирането.

Форматиране на числа


Стандартните форматиращи низове позволяват задаването на изгледа при отпечатване на основните типове числови стойности. Форматиращият низ трябва да е във вида Axx, където А е символ от азбуката, наречен фор­матен спецификатор (format specifier), a xx е незадължително число между 0 и 99 (указател за точност), което задава броя на значимите цифри или броя на нулите след десетичната запетая. Форматиращият низ не трябва да съдържа празни места.

Форматният спецификатор трябва да е един от позволените форматиращи символи (по-важните от тях са изброени в таблицата по-долу). В противен случай се получава изключение от тип FormatException.



Специфика­тор на фор­матиране

Име

Описание

C или c

валута

Числото се преобразува в низ, който пред­ставлява парична стойност в стандартния формат за валута на текущата нишка (ако не бъде зададен изрично друг формат за валута – NumberFormatInfo обект).

D или d

десетична стойност

Числото се преобразува в низ от десетични цифри (0-9), предхождани от минус, ако е отрицателно. Указателят за точност опре­деля минималния брой цифри, присъстващи в получения низ. При необходимост се до­бавят нули от ляво. Този формат се под­държа само от целочислени типове.

E или e

научен (експонен­циален)

Числото се преобразува в експоненциален формат. Например числото 3.14 се записва във вида 3,140000E+000. Указателят за точност определя броя на знаците след де­сетичната запетая.

F или f

фиксирана запетая

Подаденото реално число се записва като низ с фиксирана запетая, например "3,14". Ука­зателят за точност определя броя на де­се­тичните знаци. В зависимост от култу­рата се използва различен разделител меж­ду цялата и дробната част ("." или ",").

N или n

число

Числото се преобразува в низ от вида "-d,ddd,ddd.ddd…", където всяко ‘d’ обозна­чава цифра (0-9). Низът започва със знака минус, ако числото е отрицателно. Между всяка група от три цифри в ляво от десе­тичната запетая се поставя разделител. Указателят за точност задава желания брой знаци след десетичната запетая.

P или p

процент

Числото се преобразува в проценти чрез умножение по 100. Указа­телят за точност задава желания брой десе­тични знаци.

X или x

шестнай­се­тично число

Числото се преобразува в низ от шестнай­сетични цифри. Например числото 234 се записва като "EA". Това форматиране се поддържа само от целочислени типове.

Трябва да имаме предвид, че при повечето форматиращи низове крайният вид на низа зависи от настройките в Regional Options в Control Panel, когато не е подадена изрично култура. Класът NumberFormatInfo съдържа информация за ва­лута, десетични разделители и други символи, свързани с числовите стойности. Ще го разгледаме по-подробно в секцията за интернацио­на­лизация и култури.

Следните примери демонстрират форматирането на число във вид на валута, експоненциален запис, шестнайсетичен запис и процент.



int i = 100;

string formatted = i.ToString("C");

Console.WriteLine(formatted);

// Result: 100,00 лв

// (при български настройки на Windows)
double d = -3.27e38;

Console.WriteLine("{0:E}", d);

// Result: -3,270000E+038
int value = 29690;

Console.WriteLine("0x{0:X8}", value);

// Result: 0x000073FA
double p = 0.3378;

Console.WriteLine("{0:P}", p);

// Result: 33,78 %


В горния пример видът на получения низ зависи от регионалните настрой­ки на машината, на която е стартиран.

Форматиране със собствени шаблони


При отпечатване на числа имаме възможност да задаваме и собствени шаблони за форматиране чрез използването на следните символи:

Форматиращ знак

Име

Описание

#

диез

Замества една цифра, като при липса на цифра не се отпечатва нищо.

0

нула

Замества една цифра, като при липса на цифра се отпечатва 0.

.

точка

Задава десетичната запетая.

,

запетая

Задава разделител между хилядите.

Следният пример показва как могат да се ползват тези символи за създа­ване на собствени шаблони:

long tel = 359888123456;

Console.WriteLine("Тел. {0:(+###) (##) ### ## ##}", tel);

// Result: Тел. (+359) (88) 812 34 56
decimal sum = 4317.60M;

Console.WriteLine("Sum = {0:###,###,##0.00}", sum);

// Result: Sum = 4 317,60


Както и в предходния пример, видът на получения низ зависи от регио­налните настройки на машината, на която е стартиран. Те задават вида на десетичната точка, както и разделителите между хилядите.

Отместване при форматирането


При отпечатване с форматиране можем да задаваме ширината на полето, в което трябва да се запише резултатът. Ширината се указва след номера на аргумента, отделена със запетая. Например {0,10} разполага нулевият аргумент в пространство от 10 символа, като допълва отляво с интервали, а {0,-8} разполага нулевият аргумент в пространство от 8 символа, като допълва отдясно с интервали.

decimal sum = 4317.60M;

Console.WriteLine("Sum = |{0,16:C}|", sum);

// Result: Sum = | 4 317,60 лв|
string ip = "62.44.14.203";

Console.WriteLine("IP: |{0,-20}|", ip);

// Result: IP: |62.44.14.203 |


Освен чрез стандартните форматиращи низове, начинът на отпечатване на стойностите може да се контролира и чрез потребителско формати­ране.

В горния пример, понеже се използва типът decimal, константата, която му се присвоява като стойност, трябва да завършва с буквата "M". В езика C# тази буква указва, че константната стойност е от тип System.Decimal. Ако тази буква се пропусне, компилаторът ще счита константата за число от тип double. По подобен начин константите от тип long трябва да завършват на "L", а константите от тип float – на "F".


Форматиране на дати и часове


Форматирането на дати и часове се извършва чрез шаблони за формати­ране. Тези шаблони представляват символни низове, които се състоят от форматиращи символи (букви от латинската азбука, които се заместват с елемент от подадената дата или час) и други символи, които се използват без изменение. В таблицата са дадени най-често използваните форма­тиращи символи:

Форматиращ символ

Описание

d, dd

Замества деня от подадената дата (във вариант съот­ветно с и без водеща нула).

M, MM

Замества месеца от подадената дата (във вариант съ­ответно с и без водеща нула).

MMMM

Замества пълното име на месеца от подадената дата на езика, свързан с културата на текущата нишка.

yy, yyyy

Замества годината от подадената дата (в двуцифрен или четирицифрен формат).

h, hh, H, HH

Замества часа от подадените дата и време (във вариант съ­ответно с и без водеща нула). Във варианта с малки бук­ви се използва 12-часов формат, а във варианта с главни букви - 24-часов формат.

m, mm

Замества минутата от подадените и време (във вариант съ­ответно с и без водеща нула).

s, ss

Замества секундата от подадените и време (във вариант съ­ответно с и без водеща нула).

/

Замества текущия разделител между дни, месеци и години. Разделителят се взима от текущата култура (от свойството DateTimeFormatInfo.DateSeparator).

:

Замества текущия разделител между часове, минути и секунди. Разделителят се взима от текущата култура (от свойството DateTimeFormatInfo.TimeSeparator).

При отпечатване на дата може да се зададе или да не се зададе шаблон. Ако шаблон не бъде зададен, се използва шаблонът по подразбиране за текущата култура. От текущата култура зависят и някои от форматира­щите символи, например разделителите.

Форматиране на дати и часове – пример


Ще демонстрираме използването на форматиращи низове за дати с някол­ко примера:

DateTime now = DateTime.Now;

Thread.CurrentThread.CurrentCulture=CultureInfo.InvariantCulture;

Console.WriteLine("{0:d.MM.yyyy - HH:mm:ss} ", now);

// Result: 28.09.2005 - 19:25:02


Thread.CurrentThread.CurrentCulture = new CultureInfo("bg-BG");

DateTime birthDate = new DateTime(1980, 06, 14, 06, 10, 00);

Console.WriteLine(

"Аз съм роден на {0:d MMMM yyyy г., в HH:mm часа}.",

birthDate);

// Result: Аз съм роден на 14 Юни 1980 г., в 06:10 часа.


Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");

Console.WriteLine(DateTime.Now);

// Result: 9/28/2005 7:24:49 PM

Потребителско форматиране


Типовете могат да дефинират свое собствено форматиране. За целта е нужно типът да имплементира интерфейса IFormattable и да предоставя свой метод ToString(string format, IFormatProvider formatProvider).

Възможно е също да си дефинираме собствен метод, който да се грижи за форматиране на произволен тип. За да направим наш метод Format(), който да използваме за форматирането на даден тип, трябва да импле­ментираме ICustomProvider и IFormatProvider.


Потребителско форматиране за собствени типове


Можем да добавим възможност за обработка на дефинирани от нас форма­тиращи низове в дефинираните от нас собствени типове. За целта трябва в нашите типове да имплементираме интерфейса IFormattable и метода му ToString(). По този начин ще имаме контрол върху това какви форма­тиращи низове ще разпознава нашият тип.

Методът ToString() на IFormattable приема като параметри формати­ращ низ и доставчик на формат (format provider). Ако форматиращият низ е празен или null, се извършва форматиране по подразбиране. Ако доставчикът на форматиране е null, се използва този по подразбиране.

Следва пример за тип, поддържащ няколко вида форматиращи низове:

class Money : IFormattable

{

private double mAmmount;


public Money(double aAmmount)

{

mAmmount = aAmmount;



}
public string ToString(string aFormat,

IFormatProvider aFormatProvider)

{

if (aFormat == "USD")



{

return String.Format(

"${0:###,###,##0.00}", mAmmount);

}

else if (aFormat == "BGL")



{

return String.Format(

"{0:###,###,##0.00} лв.", mAmmount);

}

else



{

throw new FormatException(String.Format(

"Invalid format: {0}", aFormat));

}

}


static void Main()

{

Money m = new Money(27000);



Console.WriteLine("В долари: {0:USD}", m);

// Result: В долари: $27 000,00

Console.WriteLine("В лева: {0:BGL}", m);

// Result: В лева: 27 000,00 лв.

try

{

Console.WriteLine("В евро: {0:EUR}", m);



}

catch (FormatException fe)

{

Console.WriteLine("Error: {0}", fe.Message);



}

// Result: Error: Invalid format: EUR

}

}


Класът Money от примера реализира интерфейса IFormattable и може да бъде форматиран с низовете "USD" и "BGL".

Потребителско форматиране за съществуващи типове


Можем да управляваме форматирането на вече съществуващите типове, като създаваме собствени класове, доставчици на формат. Те трябва да имплементират интерфейсите ICustomFormatter и IFormatProvider. При извикването на метода ToString(), прави­лата, по които да ще се извър­ши форматирането, се определят от подадения като параметър доставчик на формат. Няма да се спираме не повече детайли. Конкретен пример за използването на ICustomFormatter и IFormatProvider има в MSDN Library, в помощната информация за класа IFormatProvider.




Сподели с приятели:
1   ...   60   61   62   63   64   65   66   67   ...   73




©obuch.info 2024
отнасят до администрацията

    Начална страница