Урок 9. Просмотр вперед и назадВсе выражения, использованные к настоящему моменту, соответствовали тексту, но иногда необходимо использовать выражения для того, чтобы лишь отметить позицию текста, который будет проверяться на совпадение в дальнейшем (в отличие от текста, соответствие с которым уже установлено). Для этого используется поиск контекстна (возможность просмотра вперед и назад, которая и будет объясняться в этом уроке). Что такое поиск контекста
Мы снова начнем с примера. Нужно найти заголовок Web-страницы; заголовки HTML-страницы помещаются между тегами Текст <HEAD> <TITLE>Ben Forta's Homepage</TITLE> </HEAD> Регулярное выражение <[tT][iI][tT][lL][eE]>.*</[tT][iI][tT][lL][eE]> Результат
<HEAD>
<TITLE>Ben Forta's Homepage</TITLE>
</HEAD>
Регулярное выражение Однако так ли это на самом деле? Ведь нужен был текст заголовка, а найденный нами текст содержит также открывающий и закрывающий теги заголовка. Можно ли возвратить только текст заголовка? Одно из решений может использовать подвыражения (см. урок 7, "Использование подвыражений"). С помощью подвыражений можно разбить найденный текст на три части: открывающий тег, текст и закрывающий тег. Разбив текст на части, можно извлечь только нужную часть. Но едва ли стоит искать то, что фактически не нужно, только для того, чтобы потом вручную удалить найденную часть текста. На самом деле нужно найти способ создавать шаблон так, чтобы он содержал совпадения, которые не возвращаются, иными словами, совпадения, которые используются только для того, чтобы правильно найти местоположение основного совпадения, но сами вспомогательные совпадения не рассматриваются как части найденного совпадения. Другими словами, нужно просто посмотреть вокруг искомого текста. ЗамечаниеВ этом уроке обсуждается просмотр вперед и назад. Просмотр вперед поддерживается во всех основных реализациях регулярных выражений, а просмотр назад поддерживается далеко не во всех реализациях. ЗамечаниеВ языках Java, .NET, PHP и Perl поддерживается просмотр назад (в некоторых реализациях с ограничениями), а в JavaScript и ColdFusion — не поддерживается. Просмотр вперед
При просмотре вперед определяется шаблон, который будет найден, но он не возвращается. Просмотр вперед фактически определяет подвыражение, так что часть, определяемая при просмотре вперед, форматируется как подвыражение. Синтаксически шаблон для просмотра вперед выглядит как подвыражение, которому предшествует ЗамечаниеИногда в документации по регулярным выражениям используется термин потреблять (consume) для обозначения того, что будет найдено и возвращено; о том же, что было найдено в результате просмотра вперед, говорят, что оно не потребляется, не используется (not consume). Вот пример. Следующий текст содержит список URL, и в каждом URL нужно извлечь часть, соответствующую протоколу (возможно, чтобы знать, как обработать эти URL). Текст http://www.forta.com/ https://mail.forta.com/ ftp://ftp.forta.com/ Регулярное выражение .+(?=:) Результат http://www.forta.com/ https://mail.forta.com/ ftp://ftp.forta.com/
В перечисленных URL протокол отделен от имени хоста двоеточием
Чтобы лучше понять, что делает Текст http://www.forta.com/ https://mail.forta.com/ ftp://ftp.forta.com/ Регулярное выражение .+(:) Результат http://www.forta.com/ https://mail.forta.com/ ftp://ftp.forta.com/
Подвыражение
Различие между этими двумя примерами состоит в том, что для того чтобы установить соответствие с двоеточием ЗамечаниеОперация просмотра вперед (а также и просмотра назад) фактически возвращает результат, но эти результаты всегда имеют длину 0 символов. Поэтому иногда операции поиска контекста называются операциями нулевой длины или ширины (zero-width). Замечание
Любое подвыражение можно использовать в операции просмотра вперед, для этого нужно перед подвыражением поставить Просмотр назад
Как вы уже знаете, символы Замечание
Как отличать операторы
Оператор Рассмотрим пример. Пусть в результате поиска в базе данных получен список товаров, а извлечь нужно только цены. Текст АВС01: $23.45 HGG42: $5.31 CFMX1: $899.00 ХТС99: $69.96 Total items found: 4 Регулярное выражение \$[0-9.]+ Результат АВС01: $23.45 HGG42: $5.31 CFMX1: $899.00 ХТС99: $69.96 Total items found: 4
Метасимвол
Этот шаблон отработал правильно. Но что делать, если символы Текст АВС01: $23.45 HGG42: $5.31 CFMX1: $899.00 ХТС99: $69.96 Total items found: 4 Регулярное выражение [0-9.]+ Результат АВС01: $23.45 HGG42: $5.31 CFMX1: $899.00 ХТС99: $69.96 Total items found: 4
Это, очевидно, не сработало. Действительно, Решение состоит в том, чтобы установить соответствие при просмотре назад следующим образом: Текст АВС01: $23.45 HGG42: $5.31 CFMX1: $899.00 ХТС99: $69.96 Total items found: 4 Регулярное выражение (?<=\$)[0-9.]+ Результат АВС01: $23.45 HGG42: $5.31 CFMX1: $899.00 ХТС99: $69.96 Total items found: 4
Этим мы добились цели. Шаблон
Сравните первое и последнее выражения, используемые в этом примере. Выражение Замечание
Шаблоны, используемые при просмотре вперед, могут иметь переменную длину; они могут содержать, например, Совместное использование просмотра вперед и просмотра назадОперации просмотра вперед и просмотра назад могут использоваться совместно, как показано в следующем примере (решение проблемы, поставленной в начале этого урока): Текст <HEAD> <TITLE>Ben Forta's Homepage</TITLE> </HEAD> Регулярное выражение (?<=\<[tT][iI][tT][lL][eE]>).*(?=</[tT][iI][tT][lL][eE]>) Результат
<HEAD>
<TITLE>Ben Forta's Homepage</TITLE>
</HEAD>
Выражение отработало правильно. Шаблон Замечание
Обратите внимание, что в предыдущем примере знак Отрицание поиска контекста, или негативный поиск контекстаКак уже утверждалось, просмотр вперед и просмотр назад обычно используются для того, чтобы установить соответствие с текстом, т.е. по существу определить местоположение текста, который будет возвращен (ведь именно для этого устанавливается соответствие с текстом, предшествующим искомому, и с текстом, следующим после искомого). Такие операции просмотра называются позитивным (положительным) просмотром вперед и позитивным (положительным) просмотром назад. Термин позитивный (положительный) указывает, что в данном случае операции поиска должны найти совпадение (соответствие). Несколько реже используется противоположная форма поиска контекста — негативный (отрицательный) поиск контекста. Негативный (отрицательный) просмотр вперед просматривает текст вперед для того, чтобы найти текст, который не соответствует указанному шаблону, а негативный (отрицательный) просмотр назад подобен негативному (отрицательному) просмотру вперед в том, что он тоже ищет текст, который не соответствует указанному шаблону, но отличается от негативного (отрицательного) просмотра вперед направлением просмотра — при этом типе поиска выполняется поиск назад.
Вы, возможно, ожидали, что для обозначения отрицания поиска контекста используется знак Таблица 9.1. Операции поиска контекста
ЗамечаниеВообще говоря, любая реализация регулярных выражений, поддерживающая просмотр вперед, поддерживает и положительный, и отрицательный просмотр вперед. Точно так же та реализация, которая поддерживает просмотр назад, поддерживает и положительный, и отрицательный просмотр назад. Чтобы продемонстрировать различие между положи¬тельным и отрицательным просмотрами назад, рассмотрим пример. Следующий блок текста содержит числа — цены и количества фруктов. Сначала мы получим только цены: Текст I paid $30 for 100 apples, 50 oranges, and 60 pears. I saved $5 on this order. Регулярное выражение (?<=\$)\d+ Результат I paid $30 for 100 apples, 50 oranges, and 60 pears. I saved $5 on this order.
Этот пример очень похож на пример, рассмотренный ранее. Шаблон Теперь мы сделаем противоположный поиск: определим местонахождение только количеств фруктов, а не цен: Текст I paid $30 for 100 apples, 50 oranges, and 60 pears. I saved $5 on this order. Регулярное выражение \b(?<!\$)\d+\b Результат I paid $30 for 100 apples, 50 oranges, and 60 pears. I saved $5 on this order.
И снова,
Может возникнуть вопрос: почему в этом примере в шаблоне отрицательного просмотра назад указаны границы слова (с помощью Текст I paid $30 for 100 apples, 50 oranges, and 60 pears. I saved $5 on this order. Регулярное выражение (?<!\$)\d+ Результат I paid $30 for 100 apples, 50 oranges, and 60 pears. I saved $5 on this order.
Без границ слова был также найден Резюме
Просмотр вперед и назад позволяет более гибко управлять тем, что возвращается в случае установления совпадения. Операции поиска контекста позволяют использовать подвыражения для того, чтобы определить местоположение текста, с которым будет установлено соответствие, но не использовать этот текст (иными словами, найти некоторый текст, но не включать его в тот текст, который будет выдан в качестве результата). Положительный просмотр вперед определяется с помощью |
||||||||||||