Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ооп теория

.pdf
Скачиваний:
22
Добавлен:
14.02.2015
Размер:
4 Мб
Скачать
☆

В этом фрагменте кода конструируются две строки. Первая из них создается из строк и булевых значений true и false. Для конструирования используются методы Insert и Append. Вторая строка конструируется в цикле с применением метода AppendFormat. Результатом этого конструирования является строка, в которой простые предложения исходного текста пронумерованы.

Обратите внимание, что сконструированная вторая строка передается в обычную строку класса String. Никаких проблем преобразования строк одного класса в другой класс не возникает, поскольку все объекты, в том числе, объекты класса StringBuilder, обладают по определению методом

ToString.

Обратите внимание, как выглядят результаты работы.

Рис. 14.4. Операции и методы класса StringBuilder

Емкость буфера

Каждый экземпляр строки класса StringBuilder имеет буфер, в котором хранится строка. Объем буфера - его емкость - может меняться в процессе работы со строкой. Объекты класса имеют две характеристики емкости -

текущую и максимальную. В процессе работы текущая емкость изменяется,

естественно, в пределах максимальной емкости, которая реально достаточно высока. Если размер строки увеличивается, то соответственно автоматически растет и текущая емкость. Если же размер строки уменьшается, то емкость буфера остается на том же уровне. По этой причине иногда разумно

251

уменьшать емкость. Следует помнить, что попытка уменьшить емкость до величины, меньшей длины строки, приведет к ошибке.

У класса StringBuilder имеется 2 свойства и один метод, позволяющие анализировать и управлять емкостными свойствами буфера. Напомню, что этими характеристиками можно управлять также еще на этапе создания объекта, - для этого имеется соответствующий конструктор. Рассмотрим свойства и метод класса, связанные с емкостью буфера:

свойство Capacity - возвращает или устанавливает текущую емкость буфера;

свойство MaxCapacity - возвращает максимальную емкость буфера.

Результат один и тот же для всех экземпляров класса;

метод int EnsureCapacity (int capacity) - позволяет уменьшить емкость буфера. Метод пытается вначале установить емкость, заданную параметром capacity; если это значение меньше размера хранимой строки, то емкость устанавливается такой, чтобы гарантировать размещение строки. Это число и возвращается в качестве результата работы метода.

Приведу код, в котором проводятся различные эксперименты с емкостью буфера:

//Емкость буфера

int curvol1 = txtbuild.Capacity; int curvol2 = strbuild.Capacity; int maxvol1 = txtbuild.MaxCapacity; int maxvol2 = strbuild.MaxCapacity;

Console.WriteLine("curvol1= {0}",curvol1); Console.WriteLine("curvol2= {0}",curvol2); Console.WriteLine("maxvol1= {0}",maxvol1); Console.WriteLine("maxvol2= {0}",maxvol2); int sure1 = txtbuild.EnsureCapacity(100); int sure2 = strbuild.EnsureCapacity(100); Console.WriteLine("sure1= {0}",sure1); Console.WriteLine("sure2= {0}",sure2); curvol2 = strbuild.Capacity; Console.WriteLine("curvol2= {0}",curvol2);

//ошибка! попытка установить емкость меньше длины строки

//strbuild.Capacity = 25;

252

strbuild.Capacity = 256; //так можно! curvol2 = strbuild.Capacity; Console.WriteLine("curvol2= {0}",curvol2);

//увеличим строку - емкость увеличится int len = txtbuild.Length; txtbuild.Append(txtbuild.ToString()); curvol1 = txtbuild.Capacity;

Console.WriteLine("curvol1= {0}",curvol1); //уменьшим строку

txtbuild.Remove(len, len); curvol1 = txtbuild.Capacity;

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

В этом фрагменте кода анализируются и изменятся емкостные свойства буфера двух объектов. Демонстрируется, как меняется емкость при увеличении и уменьшении размера строки. Результаты работы этого фрагмента кода показаны на рис. 14.5.

Рис. 14.5. Анализ емкостных свойств буфера

253

Тема 15. РЕГУЛЯРНЫЕ ВЫРАЖЕНИЯ СОДЕРЖАНИЕ ЛЕКЦИИ:

ПРОСТРАНСТВО ИМЕН REGULAREXPRESSION И КЛАССЫ РЕГУЛЯРНЫХ ВЫРАЖЕНИЙ

o НЕМНОГО ТЕОРИИ

o СИНТАКСИС РЕГУЛЯРНЫХ ВЫРАЖЕНИЙ

oЗНАКОМСТВО С КЛАССАМИ ПРОСТРАНСТВА

REGULAREXPRESSIONS

КЛАСС REGEX

КЛАССЫ MATCH И MATCHCOLLECTION

КЛАССЫ GROUP И GROUPCOLLECTION

КЛАССЫ CAPTURE И CAPTURECOLLECTION

ПЕРЕЧИСЛЕНИЕ REGEXOPTIONS

КЛАСС REGEXCOMPILATIONINFO

oПРИМЕРЫ РАБОТЫ С РЕГУЛЯРНЫМИ ВЫРАЖЕНИЯМИ

ПРИМЕР "ЧЕТ И НЕЧЕТ"

ПРИМЕР "ОКО И РОКОКО"

ПРИМЕР "КОК И КУК"

ПРИМЕР "ОБРАТНЫЕ ССЫЛКИ"

ПРИМЕР "ДОМ ДЖЕКА"

ПРИМЕР "АТРИБУТЫ"

254

ПРОСТРАНСТВО ИМЕН REGULAREXPRESSION И КЛАССЫ

РЕГУЛЯРНЫХ ВЫРАЖЕНИЙ

Стандартный класс String позволяет выполнять над строками различные операции, в том числе поиск, замену, вставку и удаление подстрок.

Существуют специальные операции, такие как Join, Split, которые облегчают разбор строки на элементы. Тем не менее, есть классы задач по обработке символьной информации, где стандартных возможностей явно не хватает.

Чтобы облегчить решение подобных задач, в Net Framework встроен более мощный аппарат работы со строками, основанный на регулярных выражениях. Специальное пространство имен RegularExpression, содержит набор классов, обеспечивающих работу с регулярными выражениями. Все классы этого пространства доступны для C# и всех языков, использующих каркас Net Framework. В основе регулярных выражений лежит хорошая теория и хорошая практика их применения. Полное описание, как теоретических основ, так и практических особенностей применения этого аппарата в C#, требует отдельной книги. Придется ограничиться введением в

эту интересную область работы со строками, не рассматривая подробно все классы, входящие в пространство имен RegularExpression.

НЕМНОГО ТЕОРИИ

Пусть T = {a1, a2, ....an} - алфавит символов. Словом в алфавите T

называется последовательность записанных подряд символов, а длиной слова

- число его символов. Пустое слово, не содержащее символов, обычно обозначается как e. Алфавит T можно рассматривать как множество всех слов длины 1. Рассмотрим операцию конкатенации над множествами, так,

что конкатенация алфавита T с самим собой дает множество всех слов длины

2. Обозначается конкатенация ТТ как Т2. Множество всех слов длины k

255

обозначается - Tk, его можно рассматривать как k-кратную конкатенацию алфавита T. Множество всех непустых слов произвольной длины,

полученное объединением всех множеств Tk, обозначается T+, а

объединение этого множества с пустым словом называется итерацией языка и обозначается T*. Итерация описывает все возможные слова, которые можно построить в данном алфавите. Любое подмножество слов L(T),

содержащееся в T*, называется языком в алфавите T.

Определим класс языков, задаваемых регулярными множествами.

Регулярное множество определяется рекурсивно следующими правилами:

пустое множество, а также множество, содержащее пустое слово, и

одноэлементные множества, содержащие символы алфавита, являются регулярными базисными множествами;

если множества P и Q являются регулярными, то множества,

построенные применением операций объединения, конкатенации и итерации - P>>Q, PQ, P*, Q* - тоже являются регулярными.

Регулярные выражения представляют удобный способ задания регулярных множеств. Аналогично множествам, они определяются рекурсивно:

регулярные базисные выражения задаются символами и определяют соответствующие регулярные базисные множества, например,

выражение f задает одноэлементное множество {f} при условии, что f -

символ алфавита T;

если p и q - регулярные выражения, то операции объединения,

конкатенации и итерации - p+q, pq, p*, q* - являются регулярными выражениями, определяющими соответствующие регулярные множества.

256

По сути, регулярные выражения - это более простой и удобный способ записи регулярных множеств в виде обычной строки. Каждое регулярное множество, а, следовательно, и каждое регулярное выражение задает некоторый язык L(T) в алфавите T. Этот класс языков - достаточно мощный,

с его помощью можно описать интересные языки, но устроены они довольно просто - их можно определить также с помощью простых грамматик,

например, правосторонних грамматик. Более важно, что для любого регулярного выражения можно построить конечный автомат, который распознает, принадлежит ли заданное слово языку, порожденному регулярным выражением. На этом основана практическая ценность регулярных выражений.

С точки зрения практика регулярное выражение задает образец поиска.

После чего можно проверить, удовлетворяет ли заданная строка или ее подстрока данному образцу. В языках программирования синтаксис регулярного выражения существенно обогащается, что дает возможность более просто задавать сложные образцы поиска. Такие синтаксические надстройки, хотя и не меняют сути регулярных выражений, крайне полезны для практиков, избавляя программиста от ненужных сложностей. (В Net Framework эти усложнения, на мой взгляд, чрезмерны. Выигрывая в мощности языка, проигрываем в простоте записи его выражений.)

Синтаксис регулярных выражений

Регулярное выражение на C# задается строковой константой. Это может быть обычная или @-константа. Чаще всего, следует использовать именно @-

константу. Дело в том, что символ "\" широко применяется в регулярных выражениях как для записи escape-последовательностей, так и в других ситуациях. Обычные константы в таких случаях будут выдавать

257

синтаксическую ошибку, а @-константы не выдают ошибок и корректно интерпретируют запись регулярного выражения.

Синтаксис регулярного выражения простой формулой не описать, здесь используются набор разнообразных средств:

символы и escape-последовательности;

символы операций и символы, обозначающие специальные классы множеств;

имена групп и обратные ссылки;

символы утверждений и другие средства.

Конечно, регулярное выражение может быть совсем простым, например,

строка "abc" задает образец поиска, так что при вызове соответствующего метода будут разыскиваться одно или все вхождения подстроки "abc" в

искомую строку. Но могут существовать и очень сложно устроенные регулярные выражения. Приведу таблицу, (15.1) в которой дается интерпретация символов в соответствии с их делением на группы. Таблица не полна, в ней отражаются не все группы, а описание группы не содержит всех символов. Она позволяет дать общее представление о синтаксисе,

которое будет дополнено большим числом примеров. За деталями придется обращаться к справочной системе, которая, к сожалению, далеко не идеальна для данного раздела.

Повторяю, данная таблица не полна. В ней не отражены, например, такие категории, как подстановки, обратные ссылки, утверждения.

Для приведенных категорий также не дан полный список возможных символов.

Таблица 15.1. Символы, используемые в регулярных выражениях

258

 

Сим

 

 

Интерпретация

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

вол

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Категория: escape-последовательности

 

 

 

 

 

 

 

 

\b

 

При использовании его в квадратных скобках соответствует

 

 

 

 

символу "обратная косая черта" с кодом - \u0008

 

 

 

 

 

 

 

 

 

 

 

\t

 

Соответствует символу табуляции \u0009

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

\r

 

Соответствует символу возврата каретки \u000D

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

\n

 

Соответствует символу новой строки \u000A

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

\e

 

Соответствует символу escape \u001B

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

\040

 

Соответствует символу ASCII, заданному кодом до трех

 

 

 

 

цифр в восьмеричной системе

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

\x20

 

Соответствует символу ASCII, заданному кодом из двух

 

 

 

 

цифр в шестнадцатиричной системе

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

\u00

 

Соответствует символу Unicode, заданному кодом из

 

 

20

 

четырех цифр в шестнадцатиричной системе

 

 

 

 

 

 

Категория: подмножества (классы) символов

 

 

 

.

 

Соответствует любому символу, за исключением символа

 

 

 

 

конца строки

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

[aeio

 

Соответствует любому символу из множества, заданного в

 

 

 

 

 

u]

 

квадратных скобках

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

[^aei

 

Отрицание.

Соответствует

любому

символу,

за

 

 

ou]

 

исключением символов, заданных в квадратных скобках

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

[0-

 

Задание диапазона символов, упорядоченных по коду. Так,

 

 

9a-fA-F]

 

0-9 задает любую цифру

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

\p{n

 

Соответствует любому символу, заданному множеству с

 

 

ame}

 

именем name, например, имя Ll задает множество букв латиницы

 

 

 

 

в нижнем регистре. Поскольку все символы разбиты на

 

 

 

 

подмножества, задаваемые категорией Unicode, то в качестве

 

 

 

 

имени можно задавать имя категории

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

\P{n

 

Отрицание. Большая буква всегда задает отрицание

 

 

ame}

 

множества, заданного малой буквой

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

\w

 

Множество символов, используемых при задании

 

 

 

 

идентификаторов - большие и малые символы латиницы, цифры и

 

 

 

 

знак подчеркивания

 

 

 

 

 

 

 

 

 

 

 

 

 

\s

 

Соответствует символам белого пробела

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

\d

 

Соответствует любому символу из множества цифр

 

 

 

 

 

 

 

 

 

Категория: Операции (модификаторы)

 

 

 

*

 

Итерация. Задает ноль или более соответствий; например,

 

 

 

 

 

 

 

 

259

 

 

 

\w*

 

 

 

 

 

 

 

 

 

 

 

(abc)

 

Аналогично, {0,}

 

 

 

 

 

*.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

+

 

Положительная итерация. Задает одно или более

 

 

 

 

соответствий; например, \w+ или (abc)+. Аналогично, {1,}

 

 

 

 

 

 

 

 

 

 

 

?

 

Задает ноль или одно соответствие; например, \w? или

 

 

 

 

(abc)?. Аналогично, {0,1}

 

 

 

 

 

 

 

 

 

 

 

 

{n}

 

Задает в точности n соответствий; например, \w{2}

 

 

 

 

 

 

 

 

 

 

 

 

{n,}

 

Задает, по меньшей мере, n соответствий; например,

 

 

 

 

(abc){2,}

 

 

 

 

 

 

 

 

 

 

 

 

{n,m

 

Задает, по меньшей мере, n, но не более m соответствий;

 

 

}

 

например, (abc){2,5}

 

 

 

 

Категория: Группирование

 

 

(?<N

 

При обнаружении соответствия выражению, заданному в

 

 

ame>)

 

круглых скобках, создается именованная группа, которой дается

 

 

 

 

имя Name. Например, (?<tel> \d{7}). При обнаружении

 

 

 

 

последовательности из семи цифр будет создана группа с именем

 

 

 

 

tel

 

 

 

 

 

 

 

 

 

 

 

()

 

Круглые скобки разбивают регулярное выражение на

 

 

 

 

группы. Для каждого подвыражения, заключенного в круглые

 

 

 

 

скобки, создается группа, автоматически получающая номер.

 

 

 

 

Номера следуют в обратном порядке, поэтому полному

 

 

 

 

регулярному выражению соответствует группа с номером 0

 

 

 

 

 

 

 

 

 

 

 

 

(?im

 

Включает или выключает в группе любую из пяти

 

 

nsx)

 

возможных опций. Для выключения опции перед ней ставится

 

 

 

 

знак минус. Например, (?i-s: ) включает опцию i, задающую

 

 

 

 

нечувствительность к регистру, и выключает опцию s - статус

 

 

 

 

single-line

 

 

 

 

 

 

Знакомство с классами пространства RegularExpressions

В данном пространстве расположено семейство из одного перечисления и

восьми связанных между собой классов.

Класс Regex

Это основной класс, всегда создаваемый при работе с регулярными

выражениями. Объекты этого класса определяют регулярные выражения.

260