regulyarnyie-vyirazheniya-osnovyi (852744), страница 17
Текст из файла (страница 17)
8.2:ack '(?i)ancyent (?=ma)' rime.txtРис. 8.2. Вьтолнение положительной опережающей проверкис помощью утилиты ack в окне TerminalИспользуя утилиту ack, можно задать нечувствительность к регистру с помощью опции командной строки -i, а не с помощью встроенной опции (? i):ack -Hi 'ancyent (?=ma) • rime.txtТакже существует возможность добавления кода регулярного выражения в командус помощью опции --output:ack -i --output '$. :$ ' 'ancyent (?=ma)' rime.txtГnава 8.
Группы проверки97Это в некотором смысле обходной путь, отключающий выделение найденных совпадений, однако он работает.Отрицатеnьная опережающая проверкаОтрицательная опережающая проверка(negative lookahead; друтое название - просмотр вперед с отрицанием) - прямая противоположность положительной проверки.Под этим подразумевается, что целью сопоставления текста с шаблоном является нахождение всех соответствий заданному шаблону при условии, что за ними не следует определенный текст. Выражение для отрицательной опережающей проверки формируетсяпримерно следующим образом:(?i)ancyent (?!marinere)Это выражение отличается от ранее рассмотренного всего лишь одним символом:знак равенства(=), соответствующий положительной опережающей проверке, замененвосклицательным знаком( ! ).
Результат выполнения отрицательной опережающей проверки в окне браузера Opera представлен на рис. 8.3.RegExrMatchSamplu(?l)ancyent (7 1 marfn•r•)"'globalNySavedshow•ltt)('ter,dedL.J dotal\Quoth l"le, there wes • Shlp-·ht,ow get th•• hence, thou grey·beard l..oontmult:H,n•\w\\�"Or m�· St•Ff sl,all m•ke thee !!ikip."\dНе t,alds him .,.;tt, hls glittering еуе--·\DThe weddlng guest s:tood st:111Алd list:ens like а thгee year's child:The Marlnere haH, hls 1'dl1.The wedding·guest 11o1t.8 оп • stone,Не c�nnot chuse but hear:And thus spalat on that ancyent man.The br1ght-eyed Marinere.Тhе Shlp was c.heer'd, the HarЬour dear'd·Merтily did "� dropВ.low tt,e Kirk, below thtt H1II.Below the Ught-house top.\s\Sс•всJ(ЛАВС](•-•](a-zA-Z]Matches &n') charactet ejl(cept fo, l1nebr.ea� tf ciotilll ts '•Lt:•The Sun came up upon th@ left,Out of the Sea Cilme he IAnd he shone bright.
end on the rightWent down lnto the S•il,RegExp;.('71)aneyent ('7 merlnere}19piltt�,.ni (?,)•ncyent (') mo1rineгoiJftilgS: !iJ1 иptunng groups:group 1: ("'1)ЗЬ b1.11lt9t,li: n� c:omРис. 8.3. Выполнение положительной ретроспективной проверкис помощью приложения RegExr в браузере Opera98Глава 8. Группы проверкиВ Perl аналогичную отрицательную опережающую проверку можно выполнить с помощью следующей команды:perl -ne 'print if /(?i)ancyent (?!marinere)/' rime.txtОна приводит к такому результату.And thus spake on that ancyent man,And thus spake on that ancyent Man,Тот же результат может быть получен с помощью утилиты ack:ack -i 'ancyent (?!marinere)' rime.txtПоnожитеnьная ретроспективная проверкаПри положительной ретроспективной проверке (positive Jookbehind; другое название - просмотр назад) целью сопоставления текста с шаблоном является нахождениеискомого текста, которому предшествует определенный текст.
Вот пример соответствующего синтаксиса:(?i)(?<=ancyent) marinereПоложительной ретроспективной проверке соответствует знак "меньше чем" ( <), самвид которого подсказывает направление просмотра текста при проверке выполнения заданного условия. Используйте это выражение в RegExr, и вы сразу же увидите отличияв результате по сравнению с предыдущими примерами: вместо слова ancyent выделитсяслово marinere. Почему так происходит? Потому что левая часть шаблона представляетпроверяемое условие и не включается в захватываемую часть результата сопоставления.Чтобы сделать то же самое в Perl, используйте следующую команду:perl -ne 'print if /(?i)(?<=ancyent) marinere/' rime.txtА вот так это можно сделать с помощью утилиты ack:ack -i '(?<=ancyent) marinere' rime.txtОтрицатеnьная ретроспективная проверкаНаконец, также возможна отрицательная ретроспективная проверка (negativelookbehiпd; другое название - просмотр назад с отрицанием). Догадываетесь, как онаработает?В этом случае условие поиска заключается в том, чтобы искомому тексту не предшествовал некоторый иной текст, а в качестве напоминания о направлении поиска вновьиспользуется знак "меньше чем" (<).Используйте в RegExr следующее выражение и посмотрите, какой при этом получается результат:(?i)(?<!ancyent) marinereДля просмотра всего текста воспользуйтесь полосой прокрутки.Проделайте то же самое в Perl:perl -ne 'print if /(?i)(?<!ancyent) marinere/' rime.txtГnава 8.
Груnпы проверки99В полученном результате полностью отсутствуют какие-либо следы слова ancyent.The Marinere hath his will.The bright-eyed Marinere.The bright-eyed Marinere.The Marineres gave it biscuit-worms,Came to the Marinere's hollo!Came to the Marinere's hollo!The Marineres all 'gan work the ropes,The Marineres all return'd to workThe Marineres all 'gan pull the ropes,"When the Marinere's trance is abated."Не loves to talk with MarineresThe Marinere, whose еуе is bright,Наконец, используйте утилиту ack:ack -i '(?<!ancyent) marinere' rime.txtНа этом мы заканчиваем краткое рассмотрение одного из мощных средств современных регулярных выражений - проверки выполнения условий поиска в прямом и обратном направлении по отношению к потоку текста.В следующей главе мы рассмотрим развернутый пример разметки документа тегамиHTMLS с помощью редактора sed и Perl.О чем вы узнаnи в rnaвe 8• Как выполняется положительная и отрицательная опережающая проверка.• Как выполняется положительная и отрицательная ретроспективная проверка.На заметкуСм.
стр. 88-97 в книге Джеффри Фридла Регулярные выражения, 3-е издание (Символ-Плюс, 2008 г.).100Глава 8. Группы проверкиГЛАВА 9Разметка документа теrами HTMLSВ этой главе представлено поэтапное описание процесса разметки простого текстового документа тегами HTMLS с использованием регулярных выражений, включая и те,которые обсуждались в самом начале книги.Если бы речь шла обо мне, то я предпочел бы использовать для этого утилитуAsciiDoc. Однако, с учетом учебного характера книги, мы притворимся, что такой вещи,как AsciiDoc, просто не существует (какой позор!). Мы будем медленно продвигатьсявперед, используя те немногие инструменты, которые имеются у нас под рукой, а именно:редактор sed, Perl и собственную изобретательность.В качестве текстового документа мы по-прежнему будем использовать поэмуКольриджа, текст которой хранится в файле rime.txt.Приведенные в этой главе сценарии отлично работают с файлом rime.txt, поскольку структура этого файла нам хорошо известна.
В случае их примененияк произвольным текстовым файлам результаты будут менее предсказуемыми,однако эта глава позволит вам подготовиться к обработке более сложных текстовых структур.Сопоставяение с тегамиПрежде чем мы приступим к добавлению тегов в текст поэмы, обсудим, какой способнаиболее пригоден для поиска тегов HTML или ХМL.
Поиск можно выполнять по начальным тегам (например, <html>), по конечным тегам (например, </html>) и ещерядом других способов, но я нашел способ, отличающийся повышенной надежностью.Соответствующий шаблон находит начальные теги как при наличии атрибутов, так и вих отсутствие:<[_a-zA-Z] [ л >]*>Вот как работает это выражение.• Первый символ представляет открывающую угловую скобку ( <).• Имена элементов в ХМL-документе могут начинаться с символа подчеркивания(_) или буквы, принадлежащей к диапазону АSСП-символов, безразлично в какомрегистре - верхнем или нижнем (см.
раздел "На заметку").•За начальным символом имени может следовать любое количество символов (втом числе и нулевое), отличных от закрывающей утловой скобки(>).•Выражение завершается закрывающей утловой скобкой.Воспользуемся утилитой grep. Применим ее к содержащемуся в архиве примеровОПА-файлу lorem.dita:grep -Ео '<[_a-zA-Z] [ л >]*>' lorem.ditaВ результате выполнения этой команды получим следующий результат.<topic id="lorem"><title><body><р><р><ul><li><11><li><р><р>Чтобы находить совпадения как с начальным, так и с конечным тегом, достаточнодополнить шаблон прямой косой чертой с последующим вопросительным знаком.
Вопросительный знак делает прямую косую черту необязательной:</? [_a-zA-Z] [л >]*>В этом примере я и далее буду работать только с открывающим тегом. Для улучшениявнешнего вида выходной информации grep я часто перенаправляю ее на вход друтих инструментов, используя канал.grep -Ео '<[_a-zA-ZJ [л >]*>' lorem.dita I sort I uniq I sed�'s/ л <//;s/ id=\".*\"//;s/>$//'Это дает нам следующий отсортированный список имен ХМL-теrов.bodyliррtitletop1culВ последней главе книги мы продвинемся еще дальше.