3665

Алгоритми обробки символьної інформації

Лекция

Информатика, кибернетика и программирование

Алгоритми обробки символьної інформації. Символьна інформація — це інформація, що відображається за допомогою символів (букв, цифр, знаків операцій і ін.). IBM-сумісні комп'ютери обробляють 256 різних символів, кожен з яких кодується одним байтом. Відповідність символів і байтів задається таблицею кодування, в якому для кожного символу вказується відповідний байт.

Украинкский

2012-11-05

947.27 KB

19 чел.

Алгоритми обробки символьної інформації

Символьна інформаціяце інформація, що відображається  за допомогою символів (букв, цифр, знаків операцій і ін.).

IBM-сумісні комп'ютери обробляють 256 різних символів, кожен з яких кодується одним байтом. Відповідність символів і байтів задається таблицею кодування, в якому для кожного символу вказується відповідний байт.

Символи з кодами від 0 до 127 побудовані за стандартом ASCII (American Standard Code for Information Interchange —Американський стандартний код обміну інформацією,  читається  "аски"). Друга половина таблиці (коди 128 ... 255) в наший країні містить російські букви (кирилицю) і символи псевдографіки.

Коди 0...127 (кодування ASCII) 

Коди 128...255 (модифікований альтернативний варіант) 

Для того, щоб визначити по цих таблицях код того,або іншого символу, потрібно скласти номер рядка з номером стовпця, в яких він розташований. Так, код цифри 5 рівний 05+048 = 053.

Символьна інформація в алгоритмах і програмах описується даними двох типів: символьним і літерним. Вони відрізняються один від одного тим, що значенням символьної змінної є один символ, а літерноюрядок символів.

Для даних символьного і літерного типів застосовані операції зчеплення (з'єднання, конкатенації) і порівняння (<,   >,   <=,   >=  =,   <>)порівнювати можна рядки різної довжини. Порівняння здійснюється зліва направо відповідно до ASCII-кодів відповідних символів.   Так, рядок   "стіл"   менше рядка   "стілець",   рядок   "teacher"  більше рядка   "people"  , а рядок   "пар"   менше рядка "парад".

По зрозумілих причинах у перших мовах програмування строковому типу приділялося набагато менше уваги, ніж арифметичному типу, або масивам. Тому в різних мовах рядка представлений по-різному й стандарт на строковий тип склався відносно недавно. Коли говорять про строковий тип, то звичайно розрізняють тип, що представляє:

  •  окремі символи, найчастіше, його називають типом char;
  •  рядка постійної довжини, часто вони представляються масивом символів;
  •  рядка змінної довжини - це, як правило, тип string, що відповідає сучасному поданню про строковий тип.

Символьний тип char, що представляє окремий випадок рядків - довжиною 1, корисний у багатьох завданнях. Основні операції над рядками - це розбір і збірка. При їхньому виконанні доводиться, найчастіше, доходити до кожного символу рядка. Ефективно реалізуються звичайні операції над рядками - визначення входження одного рядка в іншу, виділення підрядка, заміна символів рядка. Однак помітьте, подання рядка масивом символів добре тільки для рядків постійної довжини. Масив не пристосований до зміни його розмірів, вставки або видаленню символів (підрядків).

Найбільше часто використовуваним стрічковим типом є тип, звичайно називаний string, що задає рядок змінної довжини. Над цим типом допускаються операції пошуку входження одного рядка в інший, операції вставки, заміни й видалення підрядків.

Клас char

В C# є символьний клас Char, заснований на класі System.Char і що використає двобайтне  кодування Unicode подання символів. Для цього типу в мові визначені символьні константи - символьні літерали. Константу можна задавати:

  •  символом, укладеним в одинарні лапки;
  •  escape-послідовністю, що задає код символу;
  •  Unicode-послідовністю, що задає Unicode-код символу.

От кілька прикладів оголошення символьних змінних і роботи з ними:

public void TestChar()

{

char ch1='A', ch2 ='\x5A', ch3='\u0058';

char ch = new Char();

int code; string s;

ch = ch1;

//перетворення символьного типу в тип int  

code = ch; ch1=(char) (code +1);   

//перетворення символьного типу в рядок

//s = ch;  

s = ch1.ToString()+ch2.ToString()+ch3.ToString();

Console.WriteLine("s= {0}, ch= {1}, code = {2}",

s, ch, code);

}//TestChar

Три символьні змінні ініціалізовані константи, значення яких задані трьома різними способами. Змінна ch оголошується в об'єктному стилі, використовуючи new і виклик конструктора класу. Тип char, як і всі типи C#, є класом. Цей клас успадковує властивості й методи класу Object і має велику кількість власних методів.

 Чи існують перетворення між класом char й іншими класами? Явні або неявні перетворення між класами char й string відсутні, але, завдяки методу ToString, змінні типу char стандартним чином перетворяться в тип string. Існують неявні перетворення типу char у цілочисельні типи, починаючи з типу ushort. Зворотні перетворення цілочисельних типів у тип char також існують, але вони вже явні.

В результаті роботи процедури TestChar рядок s, отримана злиттям трьох символів, перетворених у рядки, має значення BZX, змінна ch дорівнює A, а її код - змінна code - 65.

Не раз відзначалося, що семантика присвоювання справедлива при виклику методів і заміні формальних аргументів на фактичні. Приведемо дві процедури, що виконують взаємо-зворотні операції - одержання за кодом символу й одержання символу за його кодом:

public int SayCode(char sym)

{

return (sym);  

}//SayCode

public char SaySym(object code)

{

return ((char)((int)code));

}// SaySym

Як бачите, у першій процедурі перетворення до цілого типу виконується неявно. У другий - перетворення явне. Заради універсальності вона злегка ускладнена. Формальний параметр має тип Object, що дозволяє передавати їй як аргумент код, заданий будь-яким цілочисельним типом. Платою за це є необхідність виконувати два явних перетворення.

Таблиця 15.1. Статичні методи й властивості класу Char

Метод

Опис

GetNumericValue

Повертає чисельне значення символу, якщо він є цифрою, і (-1) у противному випадку

GetUnicodeCategory

Всі символи розділені на категорії. Метод повертає Unicode категорію символу. Нижче наведений приклад

IsControl

Повертає true, якщо символ є керуючим

IsDigit

Повертає true, якщо символ є десятковою цифрою

IsLetter

Повертає true, якщо символ є буквою

IsLetterOrDigit

Повертає true, якщо символ є буквою або цифрою

IsLower

Повертає true, якщо символ заданий у нижньому регістрі

IsNumber

Повертає true, якщо символ є числом (десяткової або шіснадцятковою цифрою)

IsPunctuation

Повертає true, якщо символ є розділовим знаком

IsSeparator

Повертає true, якщо символ є роздільником

IsSurrogate

Деякі символи Unicode з кодом в інтервалі [0x1000, 0x10FFF] представляються двома 16-бітними "сурогатними" символами. Метод повертає true, якщо символ є сурогатним

IsUpper

Повертає true, якщо символ заданий у верхньому регістрі

IsWhiteSpace

Повертає true, якщо символ є "білим пробілом". До білих пробілів, крім пробілу, ставляться й інші символи, наприклад, символ кінця рядка й символ перекладу каретки

Parse

Перетворить рядок у символ. Природно, рядок повинен складатися з одного символу, інакше виникне помилка

ToLower

Приводить символ до нижнього регістра

ToUpper

Приводить символ до верхнього регістра

MaxValue, MinValue

Властивості, що повертають символи з максимальним і мінімальним кодом. Символи, що повертають, не мають видимого образа

Клас Char, як і всі класи в C#, успадковує властивості й методи батьківського класу Object. Але в нього є й власні методи й властивості, і їх чимало. Зведення цих методів наведені в таблиці 1.

Більшість статичних методів перевантажені. Вони можуть застосовуватися як до окремого символу, так і до рядка, для якого вказується номер символу для застосування методу. Основну групу становлять методи Is, украй корисні при розборі рядка. Приведемо приклади, у яких використаються багато хто з перерахованих методів:

public void TestCharMethods()

{

Console.WriteLine("Статичні методи класу char:");

char ch='a', ch1='1', lim =';', chc='\x';

double d1, d2;

d1=char.GetNumericValue(ch); d2=char.GetNumericValue(ch1);

Console.WriteLine("Метод GetNumericValue:");

Console.WriteLine("sym 'a' - value {0}", d1);

Console.WriteLine("sym '1' - value {0}", d2);

System.Globalization.UnicodeCategory cat1, cat2;

cat1 =char.GetUnicodeCategory(ch1);

cat2 =char.GetUnicodeCategory(lim);

Console.WriteLine("Метод GetUnicodeCategory:");

Console.WriteLine("sym '1' - category {0}", cat1);

Console.WriteLine("sym ';' - category {0}", cat2);

Console.WriteLine("Метод IsControl:");

Console.WriteLine("sym '\x' - IsControl - {0}", 

char.IsControl(chc));

Console.WriteLine("sym ';' - IsControl - {0}",

char.IsControl(lim));

Console.WriteLine("Метод IsSeparator:");

Console.WriteLine("sym ' ' - IsSeparator - {0}",

char.IsSeparator(' '));

Console.WriteLine("sym ';' - IsSeparator - {0}",

char.IsSeparator(lim));

Console.WriteLine("Метод IsSurrogate:");

Console.WriteLine("sym '\u10FF' - IsSurrogate - {0}",

char.IsSurrogate('\u10FF'));

Console.WriteLine("sym '\\' - IsSurrogate - {0}",

char.IsSurrogate('\\'));

string str = "\U00010F00";

//Символи Unicode в інтервалі [0x10000,0x10FFF]

//представляються двома 16-бітними сурогатними символами

Console.WriteLine("str = {0}, str[0] = {1}", str, str[0]);    

Console.WriteLine("str[0] IsSurrogate - {0}",

char.IsSurrogate(str, 0));

Console.WriteLine("Метод IsWhiteSpace:");

str ="пробіли, пробіли!" + "\x" + "\x" + "Усюди пробіли!";  

Console.WriteLine("sym '\x ' - IsWhiteSpace - {0}",

char.IsWhiteSpace('\x'));

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

Console.WriteLine("й її пробіли - символ 8 {0},символ 17 {1}",

char.IsWhiteSpace(str,8), char.IsWhiteSpace(str,17));

Console.WriteLine("Метод Parse:");

str="A";

ch = char.Parse(str);

Console.WriteLine("str:{0}  char: {1}",str, ch);

Console.WriteLine("Мінімальне й максимальне значення:{0}, {1}",

char.MinValue.ToString(), char.MaxValue.ToString());

Console.WriteLine("Їхні коди: {0}, {1}",

SayCode(char.MinValue), SayCode(char.MaxValue));

}//TestCharMethods

Результати консольного виводу, породженого виконанням методу, зображені на мал. 15.1.

Рис. 15.1  Виклики статичних методів класу char

Крім статичних методів, у класу Char є й динамічні. Більшість із них - це методи батьківського класу Object, успадковані й перепевні в класі Char. Із власних динамічних методів варто відзначити метод CompareTo, що дозволяє проводити порівняння символів. Він відрізняється від методу Equal тим, що для незбіжних символів видає "відстань" між символами відповідно до їх упорядкованості в кодуванні Unicode. Приведу приклад:

public void testCompareChars()

{

char ch1, ch2;

int dif;

Console.WriteLine("Метод CompareTo");

ch1='A'; ch2= 'Z';

dif = ch1.CompareTo(ch2);

Console.WriteLine("Відстань між символами {0}, 

{1} = {2}", ch1, ch2, dif);

ch1='а'; ch2= 'А';

dif = ch1.CompareTo(ch2);

Console.WriteLine("Відстань між символами {0}, 

{1} = {2}", ch1, ch2, dif);

ch1='Я'; ch2= 'А';

dif = ch1.CompareTo(ch2);

Console.WriteLine("Відстань між символами {0}, 

{1} = {2}", ch1, ch2, dif);

ch1='A'; ch2= 'A';

dif = ch1.CompareTo(ch2);

Console.WriteLine("Відстань між символами {0}, 

{1} = {2}", ch1, ch2, dif);

ch1='А'; ch2= 'A';

dif = ch1.CompareTo(ch2);

Console.WriteLine("Відстань між символами {0}, 

{1} = {2}", ch1, ch2, dif);

ch1='Е'; ch2= 'А';

dif = ch1.CompareTo(ch2);

Console.WriteLine("Відстань між символами {0}, 

{1} = {2}", ch1, ch2, dif);

}//TestCompareChars

Результати порівняння зображені на мал. 2.

Рис. 15.2.  Порівняння символів

Клас char[] - масив символів

У мові C# визначений клас Char[], і його можна використати для подання рядків постійної довжини. Більше того, оскільки масиви в C# динамічні, то розширюється клас завдань, у яких можна використати масиви символів для подання рядків. Так що є сенс розібратися, наскільки добре C# підтримує роботу з таким поданням рядків.

Насамперед, відповімо на запитання,  чи задає масив символів C# рядок , що закінчується нулем? Відповідь: ні, не задає. Масив char[] - це звичайний масив. Константа, що задає рядок символів, належить класу String, а в C# не визначені взаємні перетворення між класами String й Char[], навіть явні. У класу String є, щоправда, динамічний метод ToCharArray, що задає подібне перетворення. Можливо також посимвольно передати вміст змінної string у масив символів. Приведемо приклад:

public void TestCharArAndString()

{

//масиви символів

//char[] str1 = "Hello, World!";

//помилка: немає перетворення класу string у клас char[]

string hello = "Здраствуй, Мир!";

char[] str1 = hello.ToCharArray();

PrintCharAr("str1",str1);

//копіювання подстроки

char[] World = new char[3];

Array.Copy(str1,12,World,0,3);   

PrintCharAr("World",World);

Console.WriteLine(CharArrayToString(World));

}//TestCharArAndString

Закоментовані оператори на початку цієї процедури показують, що пряме присвоювання рядка масиву символів неприпустимо. Однак метод ToCharArray, яким володіють рядки, дозволяє легко перебороти ці труднощі. Ще одну можливість перетворення рядка в масив символів надає статичний метод Copy класу Array.

У нашому прикладі частина рядка str1 копіюється в масив World. По ходу справи в методі викликається процедура PrintCharAr класу Testing, що друкує масив символів як рядок. Ось її текст:

void PrintCharAr(string name,char[] ar)

{

Console.WriteLine(name);

for(int i=0; i < ar.Length; i++)

Console.Write(ar[i]);

Console.WriteLine();

}//PrintCharAr

Метод ToCharArray дозволяє перетворити рядок у масив символів. На жаль, зворотна операція не визначена, оскільки метод ToString, яким, звичайно ж, володіють всі об'єкти класу Char[], друкує інформацію про клас, а не вміст масиву. Ситуацію легко виправити, написавши підходящу процедуру. Ось текст цієї процедури CharArrayToString, викликаної в нашому тестованому прикладі:

string CharArrayToString(char[] ar)

{

string result="";

for(int i = 0; i< ar.Length; i++) result += ar[i];

return(result);

}//CharArrayToString

Клас Char[], як і всякий масив^-масив-клас-масив в C#, є спадкоємцем не тільки класу Object, але й класу Array, і, отже, має всі методи батьківських класів. А є чи в нього специфічні методи, які дозволяють виконувати операції над рядками, представленими масивами символів? Таких спеціальних операцій немає. Але деякі перевантажені методи класу Array можна розглядати як операції над рядками. Наприклад, метод Copy дає можливість виділяти й заміняти підстрічку в тілі рядка. Методи IndexOf, LastIndexOf дозволяють визначити індекси першого й останнього входження в рядок деякого символу. На жаль, їх не можна використати для більше цікавої операції - знаходження індексу входження підрядка в рядок. При необхідності таку процедуру можна написати самому. Ось як вона виглядає:

int IndexOfStr( char[]s1, char[] s2)

{

//повертає індекс першого входження підстрічки s2 в 

//рядок s1

int i =0, j=0, n=s1.Length-s2.Length; bool found = false;

while( (i<=n) && !found)

{

j = Array.IndexOf(s1,s2[0],i);

if (j <= n)

{

found=true; int k = 0;

while ((k < s2.Length)&& found)

{

found =char.Equals(s1[k+j],s2[k]); k++;

}

}

i=j+1;

}

if(found) return(j); else return(-1);

}//IndexOfStr

У реалізації використається метод IndexOf класу Array, що дозволяє знайти початок збігу рядків, після чого перевіряється збіг інших символів. Реалізований тут алгоритм є найочевиднішим, але далеко не найефективнішим.

А тепер розглянемо процедуру, у якій визначаються індекси входження символів і підстрічок у рядок:

public void TestIndexSym()

{  

char[] str1, str2;

str1 = "рококо".ToCharArray();  

//визначення входження символу 

int find, lind;

find= Array.IndexOf(str1,'о');

lind = Array.LastIndexOf(str1,'о');

Console.WriteLine("Індекси входження про у рококо:{0},{1};

", find, lind);

//визначення входження підстрічки

str2 = "доля".ToCharArray();

find = IndexOfStr(str1,str2);

Console.WriteLine("Індекс першого входження доля в 

рококо:{0}", find);

str2 = "око".ToCharArray();

find = IndexOfStr(str1,str2);

Console.WriteLine("Індекс першого входження око в 

рококо:{0}", find);

}//TestIndexSym

У цій процедурі спочатку використаються стандартні методи класу Array для визначення індексів входження символу в рядок, а потім створений метод IndexOfStr для визначення індексу першого входження підстрічки. Коректність роботи методу перевіряється на різних рядках. Ось результати її роботи.

Рис. 15.3.  Індекси входження підрядка в рядок

Клас String

У попередній лекції ми говорили про символьний тип char і рядках постійної довжини, що задають масивом символів. Основним типом при роботі з рядками є тип string, що задає рядка змінної довжини. Клас String у мові C# ставиться до посилальних типів. Над рядками - об'єктами цього класу - визначений широкий набір операцій, що відповідає сучасному поданню про те, як повинен бути влаштований стрічковий тип.

Оголошення рядків. Конструктори класу string

Об'єкти класу String оголошуються як всі інші об'єкти простих типів - з явною або відкладеною ініціалізацією, з явним або неявним викликом конструктора класу. Найчастіше, при оголошенні стрічкової змінної конструктор явно не викликається, а ініціалізація задається стрічковою константою. Але в класу String досить багато конструкторів. Вони дозволяють сконструювати рядок з:

  •  символу, повтореного задане число раз;
  •  масиву символів char[];
  •  частини масиву символів.

Деяким конструкторам як параметр ініціалізації можна передати рядок, заданий типом char*. Але все це небезпечно, і подібні приклади приводитися й обговорюватися не будуть. Приведу приклади оголошення рядків з викликом різних конструкторів:

public void TestDeclStrings()

{

//конструктори

string world = "Мир";

//string s1 = new string("s1");

//string s2 = new string();

string sssss = new string('s',5);

char[] yes = "Yes".ToCharArray();

string stryes = new string(yes);

string strye = new string(yes,0,2);

Console.WriteLine("world = {0}; sssss={1}; stryes={2};"+

" strye= {3}", world, sssss, stryes, strye);

}

Об'єкт world створений без явного виклику конструктора, а об'єкти sssss, stryes, strye створені різними конструкторами класу String.

Помітьте, не допускається явний виклик конструктора за замовчуванням - конструктора без параметрів. Немає також конструктора, якому як аргумент можна передати звичайну стрічкову константу. Відповідні оператори в тексті закоментовані.

Операції над рядками

Над рядками визначені наступні операції:

  •  присвоювання (=);
  •  дві операції перевірки еквівалентності (==) і (!=);
  •  конкатенація або зчеплення рядків (+);
  •  узяття індексу ([]).

Почну із присвоювання, що має важливу особливість. Оскільки string - це посилальний тип, то в результаті присвоювання створюється посилання на константний рядок, збережений в "купі". З однієї й тією ж стрічковою константою в "купі" може бути зв'язане небагато змінних стрічкового типу. Але ці змінні не є псевдонімами - різними іменами того самого об'єкта. Справа в тому, що стрічкові константи в "купі" не змінюються (про незмінюваність строкового типу будемо далі говорити докладно), тому коли одна зі змінних одержує нове значення, вона зв'язується з новим константним об'єктом в "купі". Інші змінні зберігають свої зв'язки. Для програміста це означає, що семантика присвоювання рядків аналогічна семантиці значимого присвоювання.

На відміну від інших посилальних типів операції, що перевіряють еквівалентність, порівнюють значення рядків, а не посилання. Ці операції виконуються як над значимими типами.

Бінарна операція "+" скріплює два рядки, приписуючи другий рядок до хвоста першої.

Можливість узяття індексу при роботі з рядками відбиває той приємний факт, що рядок можна розглядати як масив й одержувати без праці кожен її символ. Кожен символ рядка має тип char, доступний тільки для читання, але не для запису.

От приклад, у якому над рядками виконуються дані операції:

public void TestOpers()

{

//операції над рядками

string s1 ="ABC", s2 ="CDE";

string s3 = s1+s2;

bool b1 = (s1==s2);   

char ch1 = s1[0], ch2=s2[0];

Console.WriteLine("s1={0}, s2={1}, b1={2}," +

"ch1={3}, ch2={4}", s1,s2,b1,ch1,ch2);

s2 = s1;

b1 = (s1!=s2);

ch2 = s2[0];

Console.WriteLine("s1={0}, s2={1}, b1={2}," +

"ch1={3}, ch2={4}", s1,s2,b1,ch1,ch2);

//Незмінні значення

s1= "Zenon";

//s1[0]='L';

}

Стрічкові константи

Без констант не обійтися. В C# існують два види стрічкових констант:

  •  звичайні константи, які представляють рядок символів, укладені в лапки;
  •  @-константи, задані звичайною константою з попереднім знаком @.

У звичайних константах деякі символи інтерпретуються особливим чином. Зв'язано це насамперед з тим, що необхідно вміти задавати в рядку не друкують символи, що, такі, як, наприклад, символ табуляції. Виникає необхідність задавати символи їхнім кодом - у вигляді escape-послідовностей. Для всіх цих цілей використається комбінація символів, що починається символом "\" - зворотна коса риса. Так, пари символів: "\n", "\t", "\\", "\"" задають відповідно символ переходу на новий рядок, символ табуляції, сам символ зворотної косої риски, символ лапок, що вставляє в рядок, але не сигналізує про її закінчення. Комбінація "\xNNNN" задає символ, обумовлений шістнадцятирічним кодом NNNN. Хоча таке рішення виникаючих проблем зовсім природно, іноді виникають незручності: наприклад, при завданні констант, що визначають шлях до файлу, доводиться щораз подвоювати символ зворотної косої риски. Це одна із причин, по якій з'явилися @-константи.

В @-константах всі символи трактуються в повній відповідності з їхнім зображенням. Тому шлях до файлу краще задавати @-константою. Єдина проблема в таких випадках: як задати символ лапок, щоб він не сприймався як кінець самої константи. Рішенням є подвоєння символу. От відповідні приклади:

//Два види констант

s1= "\x50";

s2=@"\x50""";

b1= (s1==s2);

Console.WriteLine("s1={0}, s2={1}, b1={2}", s1,s2,b1);

s1 = "c:\\c#book\\ch5\\chapter5.doc";

s2 = @"c:\c#book\ch5\chapter5.doc";

b1= (s1==s2);

Console.WriteLine("s1={0}, s2={1}, b1={2}", s1,s2,b1);

s1= "\"A\"";

s2=@"""A""";

b1= (s1==s2);

Console.WriteLine("s1={0}, s2={1}, b1={2}", s1,s2,b1);

Гляньте на результати роботи наведених фрагментів коду, отримані при виклику процедур TestDeclStrings й TestOpers.

Рис. 15.4  Оголошення, константи й операції над об'єктами string

Незмінний клас string

У мові C# існує поняття незмінний (immutable) клас. Для такого класу неможливо змінити значення об'єкта при виклику його методів. Динамічні методи можуть створювати новий об'єкт, але не можуть змінити значення існуючого об'єкта.

До таких незмінних класів ставиться й клас String. Жоден з методів цього класу не міняє значення існуючих об'єктів. Звичайно, деякі з методів створюють нові значення й повертають як результат нові рядки. Неможливість змінювати значення рядків стосується не тільки методів. Аналогічно, при роботі з рядком як з масивом дозволене тільки читання окремих символів, але не їхня заміна. Оператор присвоювання з нашого останнього приклада, у якому робиться спроба змінити перший символ рядка, неприпустимий, а тому закоментований.

//Незмінні значення

s1= "Zenon"; ch1 = s1[0];

//s1[0]='L';

Статичні властивості й методи класу String

Таблиця 15.2. Статичні методи й властивості класу String

Метод 

Опис

Empty 

Повертається порожній рядок. Властивість зі статусом read only

Compare

Порівняння двох рядків. Метод перевантажений. Реалізації методу дозволяють порівнювати як рядки, так і підрядки. При цьому можна враховувати або не враховувати регістр, особливості національного форматування дат, чисел і т.д.

CompareOrdinal

Порівняння двох рядків. Метод перевантажений. Реалізації методу дозволяють порівнювати як рядки, так і підрядки. Рівняються коди символів

Concat

Конкатенація рядків. Метод перевантажений, допускає зчеплення довільного числа рядків

Copy

Створюється копія рядка

Format

Виконує форматування відповідно до заданих специфікацій формату. Нижче наведене більше повний опис методу

Intern, IsIntern

Відшукується й повертається посилання на рядок, якщо така вже зберігається у внутрішньому полі даних. Якщо ж рядка немає, то перший з методів додає рядок у внутрішнє поле, другий - повертає null. Методи застосовуються звичайно тоді, коли рядок створюється з використанням будівника рядків - класу StringBuilder

Join

Конкатенація масиву рядків у єдиний рядок. При конкатенації між елементами масиву уставляються роздільники. Операція, задана методом Join, є зворотною до операції, заданої методом Split. Останній є динамічним методом й, використовуючи роздільники, здійснює поділ рядка на елементи

Метод Format

Метод Format у наших прикладах зустрічався багаторазово. Щораз, коли виконувався вивід результатів на консоль, неявно викликався й метод Format. Розглянемо оператор печатки:

Console.WriteLine("s1={0}, s2={1}", s1,s2);

Тут рядок, що задає перший аргумент методу, крім звичайних символів, містить формати, укладені у фігурні дужки. У даному прикладі використовується найпростіший вид формату - він визначає об'єкт, що повинен бути підставлений у ділянку рядка, зайнята даним форматом. Крім неявних викликів, нерідко виникає необхідність явного форматування рядка.

Давайте розглянемо загальний синтаксис як самого методу Format, так і використовуваних у ньому форматів. Метод Format, як і більшість методів, є перевантаженим і може викликатися з різним числом параметрів. Перший необов'язковий параметр методу задає провайдера, що визначає національні особливості, які використовуються в процесі форматування. Як такий параметр повинен бути заданий об'єкт, що реалізує інтерфейс System.IFormatProvider. Якщо цей параметр не заданий, то використається культура, задана за замовчуванням. От приклади двох реалізацій цього методу:

public static string Format(string, object);

public static string Format(IFormatProvider, string, params object[]);

Параметр типу string задає форматизацію рядка. Заданий рядок містить один або кілька форматів, вони розпізнаються за рахунок навколишнхй формат фігурних дужок. Число форматів, вставлених у рядок, визначає й число об'єктів, переданих при виклику методу Format. Кожен формат визначає форматування об'єкта, на який він посилається і який, після перетворення його в рядок, буде підставлений у результуючий рядок замість формату. Метод Format як результат повертає переданий йому рядок, де всі специфікації формату замінені рядками, отриманими в результаті форматування об'єктів.

Загальний синтаксис, специфікований формат, такий:

{N [,M [:<коди_форматування>]]}

Обов'язковий параметр N задає індекс об'єкта, що заміняє формат. Можна вважати, що методу завжди передається масив об'єктів, навіть якщо фактично переданий один об'єкт. Індексація об'єктів починається з нуля, як це прийнято в масивах. Другий параметр M, якщо він заданий, визначає мінімальну ширину поля, що приділяється рядку, що вставляє замість формату. Третій необов'язковий параметр задає коди форматування, що вказують, як варто форматувати об'єкт. Наприклад, код C (Currency) говорить про те, що параметр повинен форматуватися як валюта з урахуванням національних особливостей подання. Код P (Percent) задає форматування у вигляді відсотків з точністю до сотої частки.

Усе стає ясним, коли з'являються відповідні приклади. От вони:

public void TestFormat()

{

//метод Format

int x=77;

string s= string.Format("x={0}",x);

Console.WriteLine(s + "\tx={0}",x);

s= string.Format("Разом:{0,10} рублів",x);

Console.WriteLine(s);

s= string.Format("Разом:{0,6:######} рублів",x);

Console.WriteLine(s);

s= string.Format("Разом:{0:P} ",0.77);

Console.WriteLine(s);

s= string.Format("Разом:{0,4:C} ",77.77);

Console.WriteLine(s);

//Національні особливості

System.Globalization.CultureInfo ci =

new System.Globalization.CultureInfo("en-US");

s= string.Format(ci,"Разом:{0,4:C} ",77.77);

Console.WriteLine(s);

}//TestFormat

Приведем деякі коментарі до цієї процедури. Спочатку демонструється, що і явний, і неявний виклики методу Format дають той самий результат. У подальших прикладах показане використання різних специфікацій формату з різним числом параметрів і різних кодів форматування. Зокрема, показаний вивід відсотків і валют. В останньому прикладі з валютами демонструється завдання провайдером національних особливостей. Із цією метою створюється об'єкт класу CultureInfo, ініціалізірованний так, щоб він задавав особливості форматування, прийняті в США. Помітьте, клас CultureInfo успадковує інтерфейс IFormatProvider. Російські національні особливості форматування встановлені за замовчуванням. При необхідності їх можна встановити в такий же спосіб, як це зроблено для США, задавши відповідно константу "ru-RU". Результати роботи методу показані на мал. 5.

Рис. 15.5.  Результати роботи методу Format

Методи Join й Split

Методи Join й Split виконують над рядком тексту взаємно зворотні перетворення. Динамічний метод Split дозволяє здійснити розбір тексту на елементи. Статичний метод Join виконує зворотну операцію, збираючи рядок з елементів.

Заданий рядком текст найчастіше являє собою сукупність структурованих елементів - абзаців, пропозицій, слів, скобкових виражень і т.д. При роботі з таким текстом необхідно розділити його на елементи, користуючись спеціальними роздільниками елементів, - це можуть бути пробіли, дужки, розділові знаки. Практично подібні завдання виникають постійно при роботі зі структурованими текстами. Методи Split й Join полегшують рішення цих завдань.

Динамічний метод Split, як звичайно, перевантажений. Найбільше часто використовувана реалізація має наступний синтаксис:

public string[] Split(params char[])

На вхід методу Split передається один або кілька символів, інтерпритуемих як роздільники. Об'єкт string, що викликав метод, розділяється на підрядки, обмежені цими роздільниками. Із цих підрядків створюється масив, що повертає як результат методу. Інша реалізація дозволяє обмежити число елементів масиву, що повертає.

Синтаксис статичного методу Join такий:

public static string Join(string delimiters, string[] items )

Як результат метод повертає рядок, отриманий конкатенацією елементів масиву items, між якими уставляється рядок роздільників delimiters. Як правило, рядок delimiters складається з одного символу, що і розділяє в результуючому рядку елементи масиву items; але в окремих випадках обмежником може бути рядок з декількох символів.

Розглянемо приклади застосування цих методів. У першому з них рядок представляє складнопідрядну пропозицію, що розбивається на прості пропозиції. У другому пропозицію розділяється на слова. Потім виробляється зворотна зборка розібраного тексту. От код відповідної процедури:

public void TestSplitAndJoin()

{

string txt = "А це пшениця, що у темному прикомірку 

зберігається," +" у будинку, що побудував Джек!";

Console.WriteLine("txt={0}", txt);

Console.WriteLine("Поділ тексту на прості пропозиції:");

string[] SimpleSentences, Words;

//розмірність масивів SimpleSentences й Words 

//установлюється автоматично відповідно до

//розмірністю масиву, що повертає методом Split

SimpleSentences = txt.Split(',');   

for(int i=0;i< SimpleSentences.Length; i++)

Console.WriteLine("SimpleSentences[{0}]= {1}",

i, SimpleSentences[i]);

string txtjoin = string.Join(",",SimpleSentences);

Console.WriteLine("txtjoin={0}", txtjoin);

Words = txt.Split(',', ' ');   

for(int i=0;i< Words.Length; i++)

Console.WriteLine("Words[{0}]= {1}",i, Words[i]);

txtjoin = string.Join(" ",Words);

Console.WriteLine("txtjoin={0}", txtjoin);

}//TestSplitAndJoin

Результати виконання цієї процедури показані на мал. 6.

Рис. 15.6. Розбір і зборка рядка тексту

Зверніть увагу, що методи Split й Join добре працюють, коли при розборі використається тільки один роздільник. У цьому випадку зборка дійсно є зворотною операцією й дозволяє відновити вихідний рядок. Якщо ж при розборі задається деякі безліч роздільників, то виникають дві проблеми:

  •  неможливо при зборці відновити рядок у колишньому виді, оскільки не зберігається інформація про те, який з роздільників був використаний при розборі рядка. Тому при зборці між елементами уставляється один роздільник, можливо, що складається з декількох символів;
  •  при розборі двох підряд, що йдуть роздільників, передбачається, що між ними перебуває порожнє слово. Зверніть увагу в тексті нашого приклада, як і покладено, після коми треба пробіл. При розборі тексту на слова як роздільники зазначені символи пробілу й коми. Із цієї причини в масиві слів, отриманому в результаті розбору, є порожні слова.

Якщо при розборі пропозиції на слова використати як роздільник тільки пробіл, то порожні слова не з'являться, але кома буде частиною деяких слів.

Як завжди, є кілька способів упоратися із проблемою. Один з них полягає в тому, щоб написати власну реалізацію цих функцій, іншої - у коректуванні отриманих результатів, третій - у використанні могутнішого апарата регулярних виражень, і про нього ми поговоримо трохи пізніше.

Динамічні методи класу String

Операції, дозволені над рядками в C#, різноманітні. Методи цього класу дозволяють виконувати вставку, видалення, заміну, пошук входження підрядкии в рядок. Клас String успадковує методи класу Object, частково їх перевизначаючи. Клас String успадковує й, отже, реалізує методи чотирьох інтерфейсів: IComparable, ICloneable, IConvertible, IEnumerable. Три з них уже розглядалися при описі класів-масивів.

Розглянемо найбільш характерні методи при роботі з рядками.

Зведення методів, наведене в таблиці 3, дає досить повну картину широких можливостей, наявних при роботі з рядками в C#. Варто пам'ятати, що клас string є незмінним. Тому Replace, Insert й інші методи являють собою функції, що повертають новий рядок як результат і не змінюють рядок, що викликав метод.

Таблица 15.3. Динамічні методи й властивості класу String

Метод

Опис

Insert

Вставляє підрядок в задану позицію

Remove

Видаляє підрядок в заданій позиції

Replace

Заміняє підрядок в заданій позиції на нову подстроку

Substring

Виділяє підрядок в заданій позиції

IndexOf, IndexOfAny, LastIndexOf, LastIndexOfAny

Визначаються індекси першого й останнього входження заданого підрядка або будь-якого символу із заданого набору

StartsWith, EndsWith

Повертається true або false, залежно від того, починається або закінчується рядок заданої підрядкової

PadLeft, PadRight

Виконує набивання потрібним числом пробілів на початку й наприкінці рядка

Trim, TrimStart, TrimEnd

Зворотні операції до методів Pad. Віддаляються пробіли на початку й наприкінці рядка, або тільки з одного її кінця

ToCharArray

Перетворення рядка в масив символів


 

А также другие работы, которые могут Вас заинтересовать

82637. Разработка автоматизированной справочной системы по методам многомерной оптимизации 1.91 MB
  Целью данной дипломной работы является разработка автоматизированной справочной системы по методам многомерной оптимизации. Метод исследования и аппаратура - персональный компьютер с операционной системой Windows XP, среда разработки Delphi 7.
82638. Деятельность Коммерческого Банка по организации выдачи и обслуживания ипотечных кредитов (на примере ОАО КБ «Севергазбанк») 2.93 MB
  Цель работы – рассмотрение системы ипотечного кредитования в Российской Федерации и прогноз перспектив ипотечного кредитования в коммерческом банке. В ходе данной работы подробно рассмотрены в I главе сущность и понятие ипотеки основные нормативно-правовые акты ипотечного кредитования а также этапы...
82639. Методы управления персоналом на ООО «Элегия» 1.33 MB
  Исследуемое предприятие не полностью использует резервы влияния качества персонала на эффективность деятельности организации в целом и ее отдельных подразделений. Поэтому необходимость всестороннего анализа конкретного влияния работы с кадровым резервом на эффективность труда обусловливает...
82640. Финансовые результаты бухгалтерской отчетности ООО «БНП» 637.78 KB
  При этом в современных условиях хозяйствования в число важнейших объектов учетного наблюдения выдвигается собственный капитал образующийся в результате получения организацией прибыли. Рост прибыли создает финансовую основу для самофинансирования деятельности предприятия...
82641. Проблемы и перспективы развития банковского надзора в россии 395 KB
  Основные направления повышения эффективности регулирования деятельности коммерческих банков в России. Целью дипломной работы является изучение основ осуществления банковского надзора и контроля за банковской деятельностью в современных условиях развития России.
82642. Разработка конструкции преобразователя напряжения 12/300В 747 KB
  Преобразователи с выходом на постоянном токе называются конверторами, а с выходом на переменном токе называются инверторами. Различие между ними заключается в том, что в конверторах, помимо переключающего устройства и трансформатора, имеется выпрямитель и сглаживающий фильтр.
82643. Разработка системы управления проектами для цифровой типографии и рекламного агентства 84.75 KB
  В дипломном проекте разработано программное обеспечение для ведения и учета производственных заказов в рекламном агентстве и цифровой типографии. Программное обеспечение позволяет существенно сократить время, требуемое для обработки заказов, а так же обеспечивает необходимую консолидацию данных.
82644. Створення програми «Простий бізнес» 3.78 MB
  Існують сервіси що дозволяють створювати великі розсилки електронних повідомлень з можливістю створення власних списків отримувачів. Порівняємо кілька найпопулярніших сервісів для масової розсилки електронних повідомлень.
82645. Анализ архитектуры открытых мультимедиа систем 14.43 MB
  Формулировка предложений по модернизации ЭУМ И и К типов для дисциплин ВПО. Модернизировать электронные учебные модули ЭУМ для дисциплин высшего профессионального образования ВПО на основе программно-архитектурных решений созданных в рамках федеральной целевой программы развития образования.