

Строки в С#
фактическим параметром, в качестве которого использована сформированная нами ранее строка str3. Результат работы некоторогосеанса работы этой программы показаннарис. 8.
Рисунок 8
Как видно из рис. 8, в этом сеансе работы мы сначала с клавиатуры ввели строку "Знаменск" и нажали клавишу Enter (тем самым это строковое значение стало содержимым строкового объекта, адресуемого ссылкой strl), затем ввели строку "Тамбов". После этого методWriteLine() использует свой единственный параметр как «форматирующую строку», то есть выводит в консольное окно весь содержащийся в ней текст, кроме управляющего символа \n, который работает как сигнал, требующий выводить вторую часть строки str3 в новую физическую строку консольногоокнапрограммы. Это мы инаблюдаемнарис. 8.
3Обработка естественноязыковых текстов
Впредыдущемразделемы уже имели возможность убедиться в том, что со строками языка С# работать несравненно легче и приятнее (и менее опасно), чем со строками языка С. В языке С# отпадает необходимость в специальной отработке техники таких действий, так все это выполняется практически без усилий. Действительно, перезапись строк выполняется операциейприсваивания
string stl = "abc";
stl = "новое содержимое"; stl = "";
аконкатенация - операциейсложения (в томчисле - комбинированнойоперацией):
string st2 = "abc"; st2 + = "добавок";
При перезаписи строк старое их содержимое для нашей программы теряется (переходит подуправлениесборщикамусора).
Ещё стоит обратить внимание на строку "", формируемую двумя подряд записанными двойными кавычками - это так называемая пустая строка, длинакоторойравна нулю.
Конкатенацию строк часто применяют на практике в случае слишком длинной форматирующейстроки методаWriteLine ():
13

Строки в С#
Console.WriteLine( "Слишком длинная форматирующая"+
"строка" );
Итак, технические проблемы работы со строками в языке С# решаются, можно сказать, сами собой.
Но помимо технических задач, существуют еще и практически важные задачи по обработке текстов естественных языков: проверка правописания, автоматический поиск фрагментов текста по образцу, выявление особенностей стиля того или иного писателя и так далееитому подобное.
Все это образцы работ с текстами, которые требуют разработки сложных алгоритмов, базирующихся на учете текстового синтаксиса и морфологии, а также на алгоритмах искусственного интеллекта, когда формулируются приблизительные правила, которыми в своей деятельности руководствуется человек (пусть, даже, и неосознанно). Перечисленные задачи являются весьма сложными и выполняются в общем случае коллективами профессиональных разработчиков предметных тем и программистов. Мы же сейчас рассмотрим небольшой спектр вспомогательных задач, лежащих в основе более сложных задач пообработкетекстов.
Для решения технических задач обработки текстов в библиотечном классе String предусмотрено большое число методов. Начнём наше рассмотрение технических задач со следующих проблем: выделить из текста первые N символов, выделить из текста последние N символов, выделить из текста N символов, начиная с позиции m-го символа. Все перечисленныепроблемы требуют применения методаSubstring ():
str.Substring(Startlndex, length);
где Startlndex - это начальная позиция в исходной строке для выделяемой подстроки, a length - длинаподстроки.
Вот иллюстрирующий примернаэту тему:
Листинг 9
1.namespace string_app
2.{
3.class Program
4.{
5.static void Main(string[] args)
6.{
7.string strl = "Знаменск";
8.string str2 = null;
9.// 1.
10.str2 = strl.Substring(0, 3);
11.Console.WriteLine(str2 + '\n');
12.// 2.
13.str2 = strl.Substring(1, 2);
14.Console.WriteLine(str2 + '\n');
15.// 3.
16.str2 = strl.Substring(strl.Length - 3, 3);
17.Console.WriteLine(str2);
14

Строки в С#
18.}
19.}
20.}
Врезультате работы программы с Листинга 9 строка - приемник str2 покажет в консольном окневполнеожидаемоесодержимое (см. рис. 9).
Действительно, рис. 9 показывает, что сначала в буферную строку str2 были успешно скопированы первые три символа исходной строки str1, затем туда же были скопированы два символа, начиная с индекса 1 (получилось значение "на"). Наконец, из исходной строки str1 были извлечены вызовом
Рисунок 9
str1.Substring( strl.Length - 3, 3 )
трипоследниесимвола (получилось строковоезначение "нск").
Кроме технической задачи об извлечении подстрок очень распространена задача о поиске внутри строки заданной подстроки с тем, чтобы изъять эту подстроку или заменить её на другую подстроку, илипростоидентифицировать текст повходящему в негофрагменту.
Для решения этой задачи следует применить методIndexOf():
ind = str.IndexOf( fragment, Startlndex );
который ищет местоположение начала подстроки fragment внутри строки str, начиная поиск с позиции Startlndex, и возвращает индекс первого символа искомого фрагмента. Если фрагмент внутритекстовогоотрезка ненаходится, то возвращается значение -1.
В связи с методом IndexOf () возникает вопрос о том, как с его помощью найти все вхождения подстроки в одну и ту же строку, а не только первое из них? Ответ на этот вопрос даёт следующая модельная учебная программа:
Листинг 10
1.namespace string_app
2.{
3.class Program
4.{
5.static void Main(string[] args)
6.{
15

Строки в С#
7.string Text = "When you say \"yes\", I say \"yes\" too";
8.string Frag = "yes";
9.string NewFrag = "no";
10.int lenOld = Frag.Length, lenNew = NewFrag.Length, ind;
11.Console.WriteLine( "Оригинальный текст: " + Text );
12.ind = Text.IndexOf( Frag, 0 );
13.while( ind >= 0 )
14.{
15.ind = Text.IndexOf( Frag, ind );
16.if( ind >= 0 )
17.{
18.Text = Text.Remove( ind, lenOld );
19.Text = Text.Insert( ind, NewFrag );
20.ind += lenNew;
21.
22.}
23.}
24.Console.WriteLine( "Обработанный текст:" + Text );
25.}
26.}
27.}
Программа с Листинга 10 призвана найти все вхождения слова "yes"1 в исходном тексте "When you say \"yes\", I say \"yes\" too" (здесь используются комбинации \" для внесения внутрь текстовой константы двойных кавычек в качестве содержательных, а не ограничительныхсимволов) изаменить егонаслово "по".
Дисплейный выводэтойпрограммы показаннарис. 10.
Рисунок 10
Из рис. 10 видно, что программа с Листинга 10 справляется с поставленной задачей. Разберемтеперь деталиееработы.
Собственно, вся работазаключенав следующихтрехстрочкахкода:
Text = Text.Remove( ind, lenOld ); Text = Text.Insert( ind, NewFrag ); ind += lenNew;
Поясним этот фрагмент: определив с помощью метода IndexOf() индекс ind искомого фрагмента, удаляем его методом Remove(), внедряем в то же место методом Insert() новый фрагмент NewFrag ипоправляемтекущий индекс ind для следующегопоиска.
Все очень просто, но нужно отметить, что методы Remove() и Insert() формируют новые строки в качестве своих возвратов, поэтому мы их и запоминаем в переменной Text (то есть
1 Данный код не является оптимальным. Имеется более простой в использовании метод Replace
16