Задачата за получаване на обект въз основа на низ е често срещана в практиката. Низът може да е получен като вход от потребителя или взет от база данни. Целта ни е да конструираме обект от стойността му, за да бъде тя по-лесно използваема в нашето приложение.
В .NET Framework за решението на тази задача е предоставено специално средство – методът Parse(string), който прави синтактичен анализ (парсване). Механизмът на неговото действие е следният: на метода Parse(string) на обект, поддържащ парсване, се подава низ, който задава валидна стойност за инстанция на такъв обект. Методът Parse(string) обработва подадения низ и връща инстанция на обекта със зададената стойност. Така методът изпълнява ролята на конструктор при създаването на обекта.
Методът Parse(string) реализира противоположната функция на метода ToString(). Подобно на него, той използва обект, доставчик на формат (FormatProvider), за да определи какво тълкуване да направи на подадения му символен низ.
Методът Parse(string) се поддържа стандартно от всички числени типове, от типа DateTime, от изброените типове (enums), както и от типовете Char и Boolean.
Парсване на числови типове
Методът Parse(string) може да парсва числа, записани в различни формати. Вариантът Parse(string, NumberStyles) позволява да се задават различни опции при парсването. NumberStyles дефинира битово поле, в което всеки бит обозначава дали е позволено или не определено поведение на входящия низ. В таблицата са дадени по-важните флагове и значението, което NumberStyles им придава:
Име на флага
|
Описание
|
None
|
Специални знаци не са позволени.
|
AllowLeadingWhite, AllowTrailingWhite
|
Указва, че при парсването трябва да се пренебрегнат празни места в началото / в края.
|
AllowLeadingSign
|
Указва, че числовият низ може да има знак в началото. Валидните символи за знак се определят културата, от свойствата PositiveSign и NegativeSign на NumberFormatInfo.
|
AllowParentheses
|
Указва, че числовият низ може да бъде заграден в двойка скоби.
|
AllowDecimalPoint
|
Указва, че числовият низ може да съдържа десетична запетая. Валидните знаци за десетична запетая се определят от свойството NumberFormatInfo на използваната култура.
|
AllowThousands
|
Указва, че числовият низ може да съдържа групиращи разделители - разделящи например стотиците от хилядите. Валидните разделители се определят от NumberFormatInfo свойството на използваната култура.
|
AllowExponent
|
Указва дали числовият низ може да е в експоненциален запис.
|
AllowCurrencySymbol
|
Указва, че числовият низ се приема като валутна информация, ако има наличен символ за валута; в противен случай се приема като число. Валидните символи за валута се определят от свойството CurrencySymbol на NumberFormatInfo.
|
AllowHexSpecifier
|
Указва, че числовият низ представлява шестнайсетична стойност. Валидните шестнайсетични стойности съдържат цифрите 0-9 и шестнайсетичните цифри A-F и a-f. Низовете не трябва да имат "0x" в началото.
|
Тъй като за всяка настройка се използва един бит от битовото поле, е лесно да се зададе комбинация от настройки. Това можем да направим с побитовия оператор | по следния начин:
string price = "3,14159";
double unitPrice = Double.Parse(price,
NumberStyles.AllowCurrencySymbol |
NumberStyles.AllowDecimalPoint |
NumberStyles.AllowExponent |
NumberStyles.AllowLeadingWhite |
NumberStyles.AllowParentheses |
NumberStyles.AllowThousands |
NumberStyles.AllowTrailingWhite);
|
С този код указваме, че желаем да получим число от потребителски низ, като позволяваме символ за валута, десетична запетая, експонента, празни символи в началото, двойка скоби, разделители на хилядите и празни символи в края. Някои от тези параметри зависят от зададените настройки за култура. По-нататък ще разгледаме влиянието на зададената култура върху метода Parse(…).
За да не се налага всеки път да изброяваме толкова много флагове, можем да използваме предефинираните комбинации от флагове в изброения тип NumberStyles – стойностите Integer, Number, Float, Currency, HexNumber и т. н., имената на които подсказват за какво служат. Ето пример за използването на предефинирана комбинация от флагове при парсването на число:
string price = "17,34 лв";
double unitPrice = Double.Parse(price, NumberStyles.Currency);
| Влияние на културата върху парсването
За да зададем изрично желаните настройки на културата, трябва да използваме варианта Parse(string, IFormatProvider). Той приема като параметър обект, имплементиращ IFormatProvider, който указва форматиращите настройки за използваната култура. IFormatProvider обектът включва информация за форматирането на числата (разделител за хилядите, знак за дробната част и др.) и за форматирането на валутата (символ за валута и местоположение).
Методът Parse(string, NumberStyles, IFormatProvider) комбинира предходните два варианта на метода. С този метод може да се зададат едновременно специфичен формат за парсваното число и специфична култура.
Парсване на числови типове – пример
Нека разгледаме няколко примера как можем да парсваме числа като задаваме комбинация от флагове за техния формат и култура:
static void Main()
{
// Set the default formatting for current thread.
// Invariant culture will be used for Console.WriteLine()
System.Threading.Thread.CurrentThread.CurrentCulture =
CultureInfo.InvariantCulture;
string s = " 000012,54 лв ";
double value = Double.Parse(s, NumberStyles.Currency,
new CultureInfo("bg-BG"));
Console.WriteLine(value); // 12.54
s = "17,345,342.38";
value = Double.Parse(s, NumberStyles.Number,
new CultureInfo("en-US"));
Console.WriteLine(value); // 17345342.38
value = Double.Parse(s, NumberStyles.Number,
new CultureInfo("bg-BG"));
// System.FormatException: Input string was not in a
// correct format.
}
|
При първото обръщение към Parse(…) подаваме низ, съдържащ информация за цена в български формат. Задаваме параметър NumberStyles. Currency, за да укажем, че това е валута и указваме, че използваме културата за България ("bg-BG"), за да може правилно да бъдат разпознати символът за валута ("лв") и знакът за дробната част (",").
При второто обръщение задаваме, че очакваме да прочетем число. Тъй като указваме американска култура ("en-US"), коректно се разпознават знакът "," като разделител на хилядите и знакът "." като обозначение за начало на дробната част. За сравнение сме показали, че ако опитаме да прочетем това число с българска култура, ще се получи изключение от тип FormatException защото в България символът "," се използва за отделяне на дробната част при реалните числа.
Парсване на дати
Класът DateTime имплементира метод Parse(…), който ни позволява да получим нов DateTime обект от низове, съдържащи дати в текстов вид.
Нека разгледаме метода DateTime.Parse(…) със сигнатура Parse(string, IFormatProvider, DateTimeStyles). Начинът на записване на датата и часа се взимат от IFormatProvider. Изброеният тип DateTimeStyles задава допълнителни настройки (дали низът може да съдържа празно място, дали да се приема текущата дата, когато е зададен само час и др.).
Освен метода Parse(…) класът DateTime имплементира и друг метод за парсване на дати и часове – ParseExact(string date, string format, IFormatProvider). Този метод позволява задаване на точния формат на датата и часа, които трябва да се парснат. За разлика от Parse(…), ParseExact(…) няма да обработи правилно датата, ако тя не отговаря абсолютно точно на зададения формат.
Форматът на датите и часовете се задава чрез шаблони за форматиране, които са същите, които разгледахме в секцията за форматиране на дати.
Парсване на дати – пример
За да илюстрираме работата с Parse(…) и ParseExact(…) ще използваме следните примери:
DateTime dt = DateTime.Parse(" Thursday,August 05, 2004 ",
new CultureInfo("en-US"), DateTimeStyles.AllowWhiteSpaces);
Thread.CurrentThread.CurrentCulture =
CultureInfo.InvariantCulture;
Console.WriteLine("{0:d}", dt);
// Result: 08/05/2004
dt = DateTime.ParseExact("5.08.2004 г. 15:47:00 ч.",
"d.MM.yyyy г. HH:mm:ss ч.", new CultureInfo("bg-BG"));
Console.WriteLine("{0:d.MM.yyyy HH:mm:ss}", dt);
// Result: 5.08.2004 15:47:00
dt = DateTime.ParseExact("15:53:21", "HH:mm:ss",
CultureInfo.InvariantCulture);
Console.WriteLine("{0:HH:mm:ss}", dt);
// Result: 15:53:21
|
При първото обръщение към метода Parse(…) указваме, че желаем да конструираме нов обект от тип DateTime, като стойността се взима от низа " Thursday,August 05, 2004 ". Вторият параметър създава нов обект CultureInfo, който указва използването на настройките за култура на САЩ (US). От изброения тип DateTimeStyles се указва стойността DateTimeStyles.AllowWhiteSpaces, която разрешава низът, който се парсва, да съдържа интервали, табулации и други символи за празно пространство.
Следващата стъпка е да зададем инвариантна култура за текущата нишка. Както видяхме в секцията за култури, инвариантната култура, не е свързана с конкретно местонахождение. В резултат на тази операция следващите извиквания на WriteLine(…) няма да отпечатват датата с настройките на операционната система, а по неутрален относно държавата начин.
За да бъде извършено правилно следващото разпознаване, подаваме на метода ParseExact(…) низ с дата, която отговаря символ по символ на шаблона на зададения от нас формат. Задаваме българска култура, за да бъдат разпознати правилно символите за час и година.
При второто обръщение към ParseExact(…) подаваме като култура CultureInfo.InvariantCulture за да укажем, че низът, който парсваме, не съдържа символи за час, година и т. н.
Сподели с приятели: |