Пятница, 24.11.2017, 10:27
Приветствую Вас Гость | RSS
Главная | Лекции | Регистрация | Вход
Меню сайта
Форма входа
Логин:
Пароль:
Категории раздела
Лекция [24]
Мини-чат
100
Поиск
Наш опрос
Оцените мой сайт
Всего ответов: 2
Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz
  • Статистика

    Онлайн всего: 1
    Гостей: 1
    Пользователей: 0
    Программирование Perl
    Главная » Статьи » Лекция » Лекция

    Лекция 8.3: Регулярные выражения

    Извлечение соответствий

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

     
    • в переменную $` помещается часть строки до найденного соответствия;
    • в переменную $& помещается часть строки, соответствующая образцу;
    • в переменную $' помещается часть строки после найденного соответствия;
    • в переменную $+ помещается последнее найденное совпадение для последнего шаблона в скобках.
     

    Если поиск окончился неудачей, то этим переменным новые значения не присваиваются. Посмотрим на примере, что сохранится в этих переменных после поиска такого соответствия:

     
    $htm= "<A HREF='http://regexp.ru/'>Регулярные выражения</A>";
    $htm =~ m|HREF=["'](\S+?)["']>|; # поиск URL сайта
     

    При успешном совпадении с шаблоном в специальные переменные будут помещены такие значения:

     
    $` = '<A '
    $& = 'HREF='http://regexp.ru/'>'
    $' = 'Регулярные выражения</A>'
    $+ = 'http://regexp.ru/'
     

    Значениями этих переменных можно пользоваться при успешном сопоставлении с образцом, например:

     
    print $& if $text =~ m/$pattern/; # выведет соответствие
     

    В регулярном выражении можно указать, что при успешном сопоставлении строки с шаблоном найденные соответствия нужно сохранить для дальнейшей обработки. С этой целью запоминаемые части шаблона нужно заключить в круглые скобки. Это также называется захватом значений. Найденные совпадения для всех заключенных в скобки частей шаблона будут доступны через специальные переменные с именами $1$2 и так далее. Составим регулярное выражение для поиска и сохранения в служебных переменных информации о сайте в том же тексте:

     
    $pattern = q|HREF=["'](\S+?)["']>([^<]+?)</A>|; # шаблон
    $htm =~ m/$pattern/; # поиск соответствия в $htm
    # в $1 = 'http://regexp.ru/'
    # в $2 = 'Регулярные выражения'
     

    Сохраненные совпадения доступны и во время обработки регулярного выражения, но через переменные с именами \1\2 и так далее. Эти переменные называются обратными ссылками (backreference) на найденные соответствия. Так, например, можно найти два одинаковых слова, стоящих в тексте друг за другом через пробелы (возможно, по ошибке):

     
    my $string = "Уже скоро скоро наступит весна!";
    my $pattern = '(\S+)\s+\1';
    # (\S+) сохранит значение 'скоро' в \1
    $string =~ m/$pattern/; # соответствие: 'скоро скоро'
     

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

     
    my $text = 'Начало в 12:25:00.'; # строка с данными
    my $pattern = '(\d\d):(\d\d):(\d\d)'; # образец для поиска
    my @time = $text =~ m/$pattern/; # сохраним в массиве
    my ($hh, $mm, $ss) = $text =~ m/$pattern/; # и в списке
     

    Можно находить любое количество соответствий образцу в одной операции сопоставления. Это делается с помощью модификатора глобального поиска.

     

    Модификаторы

    До сих пор операция сопоставления прекращала работу и возвращала результат, когда находилось первое соответствие строки указанному шаблону. Если для операции сопоставления указать модификатор /g (global), то она будет искать в строке все соответствия образцу, организуя неявный цикл обработки регулярного выражения. Например, так можно найти все числа в строке с помощью одного шаблона:

     
    my @numbers = 'Не 12.5, а 25!' =~ /(\d+)/g; # глобальный поиск
    # в @numbers будет (12, 5, 25)
     

    Ранее в этой лекции уже упоминался модификатор /i, устанавливающий поиск с игнорированием разницы между заглавными и строчными буквами. Перечислим модификаторы для операции сопоставления:

     
    • /g - искать в тексте все соответствия образцу (Global);
    • /i - искать соответствие образцу без учета регистра букв (case-Insensitive);
    • /s - рассматривать текст как одну строку (Single-line);
    • /m - рассматривать текст как многострочный (Multi-line) с учетом \n ;
    • /o - один раз откомпилировать регулярное выражение (Once);
    • /x - использовать расширенный синтаксис регулярных выражений (eXtended).
     

    Из всех модификаторов, пожалуй, самый интересный - последний, который позволяет записывать регулярные выражения в структурированном и понятном для человека виде и даже сопровождать комментариями! Так, например, можно более понятно и красиво переписать регулярное выражение, приведенное в начале лекции:

     
    m/ # начало регулярного выражения
    <A # начало тега: <A
    [^>]+? # далее могут быть любые символы, кроме >
    HREF # определение гиперссылки
    \s*=\s* # знак =, возможно окруженный пробелами
    ["']? # может быть открывающая кавычка или апостроф
    ( # начало захвата значения
    [^'" >]+? # адрес ссылки: все, кроме ',",пробела и >
    ) # конец захвата значения
    ['"]? # может быть закрывающая кавычка или апостроф
    \s* # за которым могут быть пробелы
    > # конец тега 
    /igx; # конец регулярного выражения
    # соответствует, например: <a id='ru' href="index.html">
     

    Записанное в таком виде, регулярное выражение становится доступным для понимания, анализа и модификации. А посколькурегулярные выражения компилируются, то пробельные символы и комментарии не влияют на быстродействие программы.

    Замена строк

    Кроме поиска, регулярные выражения часто применяются для замены найденных совпадений на новые значения. Для этого существует операция замены (substitution), которая пытается найти в строковой переменной соответствие образцу, а если находит, то заменяет найденную подстроку на указанное значение. Операция замены выглядит так:

     
    $variable =~ s/образец/замена/;
    # в переменной $variable отыскивается строка 'образец',
    # и если найдена, то она заменяется на 'замена'
     

    Все, что говорилось до этого про операцию сопоставления, применимо для левой части операции замены, в которой указывается образец поиска. Левая и правая части операции замены интерполируются, поэтому там могут использоваться escape-последовательности и переменные.

     
    $pattern = 'шило'; # образец
    $replacement = 'мыло'; # замена
    $text =~ s/$pattern/$replacement/; # поменять 'шило' на 'мыло'
     

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

     
    $text = 'мать любит дочь'; 
    $text =~ s/(\S+)\s+(\S+)\s+(\S+)/\3 \2 \1/; 
    # в $text будет 'дочь любит мать'
     

    Для операции замены s/// можно применять все модификаторы, упомянутые для операции сопоставления m//. Например, модификатор /g указывает, что должны быть заменены все найденные в тексте соответствия. Например:

     
    $our_computers =~ s/Windows/Linux/g;
     

    У операции замены есть дополнительный модификатор /e (expression evaluation), при включении которого заменяющая часть вычисляется как выражение. При этом в заменяющей части можно использовать ссылки на захваченные при помощи круглых скобок соответствия. Это можно применять для более "интеллектуальной" замены найденных соответствий. Так, например, можно перевести температуру из шкалы Цельсия в шкалу Фаренгейта:

     
    $text = 'Бумага воспламеняется при 233C.';
    $text =~ s/(\d+\.?\d*)C\b/int($1*1.8+32).'F'/e;
    # в $text будет: 'Бумага воспламеняется при 451F.'
     

    Применение регулярных выражений

    Регулярные выражения применяются во многих конструкциях. В функции split() первым параметром может использоватьсярегулярное выражение, которое будет служить для поиска разделителей при разделении строки на части. Так, например, можно разбить строку на подстроки по любому из пробельных символов:

     
    @substrings = split /\s+/, $text; # разбить на части
     

    Регулярные выражения часто применяются в функциях, работающих с массивами для фильтрации нужных элементов. Например,функция grep() возвратит список элементов массива, соответствующих указанному образцу:

     
    @result = grep /$pattern/, @source; # отобрать элементы
     

    С помощью функции map можно применить операцию замены в соответствии с регулярным выражением ко всем элементам массива, например:

     
    @hrefs = ('http://regex.info', 'http://regexp.ru');
    map s{http://}{}, @hrefs; # убрать 'http://' из ссылок
     

    Регулярные выражения дают программисту новый взгляд на текстовые данные: вместо отдельных символов и простых подстрок он начинает мыслить обобщенными шаблонами, что помогает ему находить более простые и эффективные решения. В таблице 8.1 для справки приведены основные обозначения, применяемые для записи регулярных выражений в Perl. Дополнительные сведения о регулярных выражениях можно почерпнуть из стандартной документации по Perl и перевода уникальной книги Джеффри Фридла "Регулярные выражения".

     
    Таблица 8.1. Основные обозначения для записи регулярных выражений
    Обозначение Описание Примеры
    // ограничители регулярного выражения по умолчанию /$pattern/
    \ отмена специального значения следующего символа m{C:\\windows}
    () группировка шаблонов или сохранение значения /(\w\w\w)+/
    | выбор из нескольких альтернатив /кошелек|жизнь/
    [] класс символов: любой символ из перечисленных /[0-9a-fA-F]/
    [^] инвертированный класс символов: любой символ, кроме перечисленных /[^0-9]/
    Метасимволы
    . любой символ, кроме \n (соответствует любому символу, включая \n с модификатором /s) /(.+)/
    \d десятичная цифра m{Время=\d+ сек}
    \D не десятичная цифра /(\D*)\d+/
    \w алфавитно-цифровой знак /\s+\w+\s+/
    \W не алфавитно-цифровой знак /\W\W\W/
    \s пробельный символ s/\s+/ /
    \S любой символ, кроме пробельного /\S+/
    Утверждения
    ^ начало строки (соответствует началу каждой строки с модификатором /m) /^\w+/
    $ конец строки (соответствует концу каждой строки с модификатором /m) /\d+$/
    \b граница слова (между \w и \W или \W и \w) /stop\b/
    \B любая позиция, кроме границы слова /stop\B/
    \A только начало строки, даже с модификатором /m /\A[#]/
    \z только конец строки, даже с модификатором /m /\w+\z/
    \Z только конец строки или перед \n в конце строки, даже с модификатором /m /\w+\Z/
    \G позиция в строке, равная значению функции pos()  
    Escape-последовательности
    \t \n \r \f \a \b управляющие символы: \b в классе символов выступает как символ Backspace (0x08), вне его - как граница слова /[\a\b\f\r\n\t]/
    \0 \x \c \N коды символов /\033\x1F\cZ/ /\x{263a}/
    \l \L \u \U \Q \E преобразующие последовательности /\Q$pattern\E/
    Квантификаторы
    * *? любое число повторений, включая 0 (максимальный и минимальный квантификаторы) /\s*/ /\S*?/
    + +? одно и более повторений (максимальный и минимальный квантификаторы) /\d+/ /\D+?/
    ? ?? ноль или одно повторение (максимальный и минимальный квантификаторы) /.?/ /[.a-z]??/
    {n} {n}? ровно n повторений (максимальный и минимальный квантификаторы) /\w{8}/ /\w{5}?/
    {n,} {n,}? n и более повторений (максимальный и минимальный квантификаторы) /\d{2,}/ /\d{5,}?/
    {n,m} {n,m}? от n до m повторений включительно (максимальный и минимальный квантификаторы) /[A-Z]{1,12}/ /[a-z]{0,3}?/
     

     

    Категория: Лекция | Добавил: mazay (13.05.2014)
    Просмотров: 156 | Рейтинг: 0.0/0
    Всего комментариев: 0
    Добавлять комментарии могут только зарегистрированные пользователи.
    [ Регистрация | Вход ]
    Создать бесплатный сайт с uCozCopyright MyCorp © 2017