Партнерка на США и Канаду по недвижимости, выплаты в крипто
- 30% recurring commission
- Выплаты в USDT
- Вывод каждую неделю
- Комиссия до 5 лет за каждого referral
UNIX-команда lex и ее GNU-версия flex получают на вход список регулярных выражений в стиле UNIX, за каждым из которых в фигурных скобках следует код, указывающий, что должен делать лексический анализатор, если найдет экземпляр этой лексемы. Такая система называется генератором лексического анализатора, поскольку на ее вход поступает высокоуровневое описание лексического анализатора и по этому описанию она создает функцию, которая представляет собой работающий лексический анализатор.
Такие команды, как lex и flex, оказались очень удобными, поскольку мощность нотации регулярных выражений необходима и достаточна для описания лексем. Эти команды способны использовать процедуру преобразования регулярного выражения в ДКА для того, чтобы генерировать эффективную функцию, разбивающую исходную программу на лексемы. Они превращают задачу построения лексического анализатора в "послеобеденную работу", тогда как до создания этих основанных на регулярных выражениях средств построение лексического анализатора вручную могло занимать несколько месяцев. Кроме того, если по какой-либо причине возникает необходимость модифицировать лексический анализатор, то намного проще изменить одно или два регулярных выражения, чем забираться внутрь загадочного кода, чтобы исправить дефект.
Пример 3.9. На рис. 3.19 приведен пример фрагмента входных данных команды lex, описывающих некоторые лексемы языка С. В первой строке обрабатывается ключевое слово else, и ее действие заключается в возвращении символьной константы (в данном примере это ELSE) в программу синтаксического анализа для дальнейшей обработки. Вторая строка содержит регулярное выражение, описывающее идентификаторы: буква, за которой следует нуль или несколько букв и/или цифр. Ее действие заключается в следующем. Сначала идентификатор заносится в таблицу символов (если его там еще нет). Затем lex выделяет найденную лексему в буфере, так что в этой части кода известно, какой именно идентификатор был обнаружен. Наконец, лексический анализатор возвращает символьную константу ID, с помощью которой в этом примере обозначаются идентификаторы.
Третий вход на рис. 3.19 предназначен для знака >=, который является двухсимволь - ным оператором. В последнем показанном примере обрабатывается односимвольный оператор =. На практике используют выражения, описывающие ключевые слова, знаки и такие символы пунктуации, как запятые или скобки, а также семейства констант, например, числа или цепочки. Многие из этих выражений чрезвычайно просты — это последовательности, состоящие из одного или нескольких определенных символов. Однако для некоторых выражений требуется вся мощь нотации регулярных выражений. Другими примерами успешного применения возможностей регулярных выражений в командах типа lex служат целые числа, числа с плавающей точкой, символьные цепочки и комментарии. □
else {возвращает (ELSE);}
[A-Za-z][A-Za-zO-9]* {код для ввода найденного идентификатора
в таблицу символов;
возвращает (ID); }
>= {возвращает (GE);}
= {возвращает (EQ);}
Рис. 3.19. Пример входных данных команды lex
Преобразование набора выражений, подобных представленным на рис. 3.19, в автомат происходит почти так же, как это было формально описано в предыдущих разделах. Сначала строится автомат для объединения всех этих выражений. Вообще говоря, этот автомат свидетельствует лишь о том, что распознана какая-то лексема. Однако если учесть конструкцию теоремы 3.7 для объединения выражений, состояние е-НКА точно указывает, к какому типу принадлежит распознанная лексема.
Единственная проблема заключается в том, что лексема может одновременно иметь сразу несколько типов; например, цепочка else соответствует не только регулярному выражению else, но и выражению для идентификаторов. В генераторе лексического анализатора применяется следующее стандартное решение: приоритет отдается выражению, находящемуся в списке первым. Таким образом, если необходимо, чтобы ключевые слова типа else были зарезервированными (т. е. не использовались в качестве идентификаторов), то они просто перечисляются в списке перед выражением для идентификаторов.
3.3.3. Поиск образцов в тексте
В разделе 2.4.1 мы отметили, что автоматы могут применяться для эффективного поиска наборов определенных слов в таких больших хранилищах данных, как Web. Хотя инструментальные средства и технология для этого пока не настолько хорошо развиты, как для лексических анализаторов, регулярные выражения все же очень полезны для описания процедур поиска желаемых образцов. Как и для лексических анализаторов, возможность перехода от естественного, описательного представления в виде регулярных выражений к эффективной (основанной на автоматах) реализации является важным интеллектуальным средством решения поставленной задачи.
Общая проблема, для решения которой технология регулярных выражений оказалась весьма полезной, заключается в описании нечетко определенного класса образцов в тексте. Нечеткость описания, в сущности, является гарантией того, что с самого начала нет нужды корректно и полно описывать образцы. Не исключено, что мы никогда не сможем получить точное и полное описание. С помощью регулярных выражений можно, не прилагая больших усилий, описывать такие образцы и быстро изменять эти описания, если результат нас не устраивает. Кроме того, "компилятор" для регулярных выражений пригоден и для преобразования записываемых выражений в выполнимый код.
В качестве примера обсудим одну типичную проблему, возникающую во многих Web - приложениях. Предположим, необходимо просмотреть огромное количество Web-страниц и отметить адреса. Возможно, мы хотим составить список электронных адресов. Или пытаемся классифицировать фирмы по их месторасположению, чтобы отвечать на запросы типа "найдите мне ресторан в пределах 10-ти минут езды от того места, где я сейчас нахожусь".
В частности, мы сосредоточим внимание на распознавании названий улиц. Что такое название улицы? Необходимо это выяснить, и, если во время тестирования программы будет установлено, что пропущены какие-то варианты, то нужно будет изменять выражения таким образом, чтобы включить все, что не было учтено. Начнем с того, что название улицы может заканчиваться словом "Street" (улица) или его сокращением "St." Однако некоторые люди живут на "Avenues" (проспектах) или "Roads" (шоссе), что тоже может быть записано в сокращенном виде. Таким образом, в качестве окончания нашего выражения можно использовать следующие варианты. Street | St\. I Avenue | Ave\. |Road | Rd\.
В этом выражении использованы обозначения в стиле UNIX с вертикальной чертой вместо + для оператора объединения. Обратите также внимание, что перед точками стоит обратная косая черта, поскольку в выражениях UNIX точка имеет специальное значение— "любой символ", а в этом случае нам необходимо, чтобы в конце сокращений стоял символ "точка".
Перед таким обозначением, как Street, должно стоять название улицы. Обычно оно состоит из прописной буквы, за которой следует несколько строчных букв. В UNIX этот образец можно описать с помощью выражения [A-Z] [a-z] *. Однако названия некоторых улиц состоят из нескольких слов, например, "Rhode Island Avenue in Washington DC". Поэтому, обнаружив, что названия такого вида пропущены, необходимо исправить наше описание таким образом, чтобы получилось следующее выражение. ' [A-Z] [a-z]* ( [A-Z] [a-z]*)*'
Это выражение начинается с группы, состоящей из прописной буквы и, возможно, нескольких строчных букв. Далее может следовать несколько групп, состоящих из пробела, еще одной прописной буквы и, возможно, нескольких строчных. В выражениях UNIX пробел является обычным символом, и, чтобы представленное выше выражение не выглядело в командной строке UNIX как два выражения, разделенных пробелом, нужно все выражение заключить в апострофы. Сами апострофы не являются частью выражения.
Теперь в адрес нужно включить номер дома. Большинство номеров домов представляют собой цепочки из цифр. Однако в некоторых номерах после цифр стоит буква, например, "123А Main St." Поэтому выражение для номеров должно включать необязательную прописную букву после цифр: [ 0-9] + [A-Z] ?. Заметьте, что мы здесь использовали UNIX-оператор + для "одной или нескольких" цифр и оператор? для "ни одной или одной" прописной буквы. Полное выражение для адресов улиц будет иметь следующий вид.
' [0-9] + [A-Z]? [A-Z] [a-z] *( [A-Z] [a-z]*)* (Street ISt\. |Avenue IAve\. |Road|Rd\.) '
Используя это выражение, получим вполне приемлемый результат. Однако в какой-то момент мы обнаружим, что пропустили следующие случаи.
Улицы, которые называются иначе, чем "street", "avenue" или "road". Например, мы упустили "Boulevard" (бульвар), "Place" (площадь), "Way" (дорога) и их сокращения. Названия улиц, которые являются числами или частично содержат числа, например, "42nd Street" (42-я улица). Почтовые ящики и маршруты сельской доставки. Названия улиц, которые не оканчиваются словом типа "Street". Например, "Е1 Camino Real in Silicon Valley". С испанского это переводится как "Королевское шоссе в Силиконовой Долине", но если сказать "El Camino Real Road" ("Королевскоешоссе шоссе"), то это будет повторением. Так что приходится иметь дело с адресами типа "2000 El Camino Real". 5. Все другие странные ситуации, которые мы даже не можем вообразить. А вы можете?
Таким образом, с помощью компилятора регулярных выражений процесс постепенного приближения к полному распознавателю адресов существенно упрощается по сравнению с использованием традиционного языка программирования.
3.3.4. Упражнения к разделу 3.3
(!) Напишите регулярное выражение для описания телефонных номеров всех видов, которые только можно себе представить. Учтите международные номера, а также тот факт, что в разных странах используется разное количество цифр в кодах областей и в локальных номерах телефонов. (!!) Напишите регулярное выражение для представления заработной платы в том виде, в котором она указывается в объявлениях о работе. Учтите, что может быть указан размер зарплаты в час, в неделю, месяц или год. Она может включать или не включать знак доллара или какой-либо другой единицы, например "К". Рядом может находиться слово или слова, обозначающие, что речь идет о зарплате. Предложение: просмотрите рекламные объявления в газетах или списки вакансий в режиме on-line, чтобы получить представление о том, какие образцы могут вам пригодиться. (!) В конце раздела 3.3.3 мы привели несколько примеров изменений, которые могут быть внесены в регулярное выражение, описывающее адреса. Модифицируйте построенное там выражение таким образом, чтобы включить все упомянутые варианты.3.4. Алгебраические законы для регулярных выражений
В примере 3.5 мы столкнулись с необходимостью упрощения регулярных выражений для того, чтобы их размер не превышал разумные пределы. Мы объяснили, почему одно выражение можно было заменить другим. Во всех рассмотренных ситуациях основной вывод заключался в том, что эти выражения оказывались эквивалентными, т. е. задавали один и тот же язык. В этом разделе будет предложен ряд алгебраических законов, позволяющих рассматривать вопрос эквивалентности двух регулярных выражений на более высоком уровне. Вместо исследования определенных регулярных выражений, мы рассмотрим пары регулярных выражений с переменными в качестве аргументов. Два выражения с переменными являются эквивалентными, если при подстановке любых языков вместо переменных оба выражения представляют один и тот же язык.
|
Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |


