lex (813547), страница 5
Текст из файла (страница 5)
Обычно они используются с цельюограничения области действия регулярных операций с низким приоритетом или группировкифрагментов регулярных выражений для применения к ним регулярных операций с высокимприоритетом. В частности, достаточно низкий приоритет имеет оператор объединения.Поэтому область действия оператора объединения распространяется на предельно длинныеальтернативы из литералов, которые находятся слева и справа от метасимвола выбора |.Вставка круглых скобок в регулярное выражение позволяет ограничить область действияоператора объединения альтернативами, которые оказались внутри них. Например, следующеерегулярное выражение обеспечивает распознавание во входном потоке либо альтернативыthis and, либо альтернативы or that, информативность которых близка к нулю:this[ ]and|or[ ]thatОднако вставка круглых скобок превращает его в следующее, потенциально более полезноерегулярное выражение:this[ ](and|or)[ ]thatЭто регулярное выражение позволяет обнаруживать во входном потоке, очевидно, болееинформативные словосочетания this and that и this or that, чем рассмотренный выше вариант безкруглых скобок.
Так происходит потому, что в данном случае круглые скобки ограничиваютобласть действия оператора объединения.Анализируя возможности скобочных регулярных выражений, следует обратить внимание наслучай использовании конструкции выбора в сочетании с якорями ^ и $, которые имеют ещеболее низкий приоритет, чем операция объединения. Такое соотношение приоритетов обычноизбавляет от необходимости применения круглых скобок при совместном использовании этихоператоров в регулярном выражении. Например, при обработке файлов электронной почтыбывает важно находить строки почтового сообщения, которые содержат директивы From: илиSubject: в начале строки. На первый взгляд кажется, что требуемое соответствие обеспечиваеттолько следующее скобочное регулярное выражение, где конструкцию выбора ограничиваюткруглые скобки, чтобы гарантировать поиск требуемых альтернатив исключительно в началахстрок почтового файла:^(From|Subject):Однако, из-за различного приоритета операций ^ и |, это регулярное выражение эквивалентноследующей конструкции выбора, где отсутствуют круглые скобки:^From:|Subject:В этом регулярном выражении якорный префикс ^ по-прежнему относится к каждой изальтернатив, потому что приоритет операции оператора циркумфлекс меньше, чем приоритетоператораобъединения.Такимобразом,обарассмотренныхрегулярныхвыражениягарантируют необходимый результат поиска директив From: и Subject: в почтовом сообщении.Однако более рациональный второй вариант, где отсутствуют круглые скобки, представляетсяболее предпочтительным.Более высокий приоритет, чем операция объединения и якорные операторы, имеютквантификаторы, поэтому любой из них применяется непосредственно к литералу, которыйнаходится слева от метасимвола, обозначающего квантификатор.
Когда требуется применитьквантификатор к регулярному выражению, оно должно быть заключено в круглые скобки.Использование этого технического приема иллюстрирует следующий пример. При обработкеразличных финансовых документов часто бывает необходимо обнаруживать записи денежныхсумм в долларах с необязательным указанием центов.
Одно из возможных решений этой задачипредоставляет следующее регулярное выражения:\$[0-9]+(\.[0-9][0-9])?Это регулярное выражение состоит из трех частей: экранированный знак доллара \$,последовательность целых десятичных цифр для идентификации количества долларов вденежной сумме [0-9]+содержащийи необязательный регулярный фрагмент (\.[0-9][0-9])?,экранированныйсимволточки,закоторымследуютдведесятичныецифры [0-9][0-9], определяющие число центов. Для группировки центовой частирегулярного выражения используются круглые скобки, чтобы получить возможностьквантифицировать находящийся в них регулярный фрагмент как будто это один символ.Еще один пример, где круглые скобки используются в целях группировки различныхфрагментов регулярного выражения, предоставляет следующая конструкция, которая можетбыть полезна для распознавания бинарных последовательностей, где чередуются символы 0и 1:(01)*|(10)*|0(10)*|1(01)*Хотя в этом регулярном выражении вместе с квантификаторами * присутствуют операторыобъединения, круглые скобки используются исключительно для группировки литералов 0 и 1 вбинарные пары.
К этим парам применяются квантификаторы *, чтобы развернуть их вбинарныепоследовательности,гдечередуютсясимволы 0и 1.Конструкциявыбораиспользуется, чтобы объединить квантифицированные фрагменты в общее регулярноевыражение, которое позволяет распознавать во входном потоке все возможные вариантычередующихся бинарных последовательностей.В частности, две первые альтернативы обеспечивают поиск бинарных последовательностей, укоторых первый и последний символы различны, например, 010101 или 101010. Две другиеальтернативы позволяют находить бинарные последовательности, где первый и последнийсимвол совпадают, например, 010 или 101.Следует отметить, что рассмотренному регулярному выражению эквивалентны следующие двеболее лаконичные конструкции:1?(01)*0?и0?(10)*1?В этих регулярных выражениях нет операторов объединения, а круглые скобки по-прежнемувыполняют функцию группировки бинарных пар для применения квантификатора *.Разумеется, возможна ситуация, когда в регулярное выражение необходимо включить круглыескобки, как для группировки, так и для ограничения его регулярных фрагментов.Комбинированное применение круглых скобок для обеспечения этих двух функцийдемонстрирует следующее регулярное выражение:((0|1)(0|1)(0|1))*Оно обозначает множество бинарных векторов, длина каждого из которых кратна трем.
Вчастности, это регулярное выражение позволяет обнаружить во входном потоке, бинарныепоследовательности 010 и 111011, длиной, соответственно, 3 и 6 символов.В рассматриваемом регулярном выражении внутренние пары круглых скобок выполняютфункцию ограничения области действия операции объединения для трех конструкций выбора.Внешние скобки обеспечивают группировку конкатенации трех внутренних скобочныхфрагментов регулярного выражения для комплексной обработки их квантификатором *.СТРУКТУРНЫЙ АНАЛИЗ РЕГУЛЯРНЫХ ВЫРАЖЕНИЙДо сих пор в качестве примеров умышленно рассматривались простые регулярные выражения,чтобы использование в них метасимволов и литералов было предельно очевидным.
Однако вбольшинстве практически интересных случаев для построения регулярных выраженийнеобходим структурный анализ лексем входного потока. Структурный подход иллюстрируютнесколько примеров конструирования регулярных выражений для распознавания времени идаты, которые рассмотрены ниже.В первом примере рассматривается проблема конструирования регулярного выражения дляпоиска записей даты, которые состоят из сокращенного названия месяца года и числа месяца.Допустим, требуется составить регулярное выражение для распознавания январских дат,например, в следующем формате: Jan 31, Jan 7 или Jan 07. На первый взгляд кажется, чтопроблему легко решает следующее регулярное выражение:Jan[ ][0123][0-9]Однако это регулярное выражение теряет корректные даты, где число задано одной цифрой безлидирующего нуля, например, Jan 7. Кроме того, оно будет находить несуществующие даты,например, Jan 00 или Jan 32. Один из способов корректного поиска даты заключается втом, чтобы разделить диапазон чисел января на три группы, которые соответствуют декадам.Каждая декада января должна специфицироваться своим фрагментом регулярного выражения.Спецификации декад объединяются в следующую итоговую конструкцию выбора:Jan[ ](0?[1-9]|[12][0-9]|3[01])В этом регулярном выражении первая альтернатива 0?[1-9] обеспечивает поиск дат первойдекады от 1-го до 9-го января, допуская запись чисел с лидирующим нулем.
Втораяальтернатива [12][0-9] позволяет распознавать даты в диапазоне чисел с 10-го по 29-еянваря. Наконец, последняя альтернатива находит завершающие даты 30-е и 31-е января.Таким образом, этим регулярным выражением оказываются покрыты все декады и числаянваря.Существует другое решение задачи поиска даты, в котором используется иной принципдекомпозиции диапазона чисел января. Его представляет следующее регулярное выражение:Jan[ ](31|[123]0|[012]?[1-9])Это регулярное выражение также объединяет три альтернативы.
Первая альтернативадопускает только одно число, 31-е января. Вторая альтернатива специфицирует регулярноевыражение для поиска дат, в которых числа кратны 10-ти, то есть 10-е, 20-е и 30-е января.Последняя альтернатива соответствует всем остальным датам января.На первый взгляд кажется, что рассмотренные регулярные выражения легко приспособить длялексического анализа даты в любом месяце года, если заменить обозначение января следующейконструкцией выбора:(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)Однаковэтомслучаевозникаетопасностьраспознаваниянесуществующихдат,например, Jun 31 (31-е июня), из-за того, что количество дней в разных месяцах годаразлично.