Опубликован: 18.06.2007 | Доступ: свободный | Студентов: 1354 / 35 | Оценка: 4.14 / 3.29 | Длительность: 12:44:00
ISBN: 978-5-94774-604-4
Лекция 8:

Пример поиска и подсветки ссылок и e-mail в тексте

< Лекция 7 || Лекция 8: 123 || Лекция 9 >
Аннотация: Рассматривается построение регулярных выражений для выделения ссылок в тексте в теги HTML.

При обработке таких текстов, как письма и сообщения на форумах, возникает задача отыскания в тексте ссылок и адресов электронной почты и выделение их в теги <a href=.

8.1 Преобразование ftp и http ссылок в теги HTML

Возьмем такой текст:

Зайдите на www.intuit.ru и посмотрите список курсов

Здесь текст www.intuit.ru является ссылкой, несмотря на отсутствие протокола http://, который подразумевается по умолчанию. В итоге наше регулярное выражение должно преобразовать этот текст к такому виду:

Зайдите на <a href="http://www.intuit.ru" target="_blank">
    www.intuit.ru</a> и посмотрите список курсов

Может быть и так, что ссылка не отделена пробелом от окружающих слов или после нее идет знак препинания (точка, запятая и т.д.) Желательно, чтобы регулярное выражение это учитывало и не включало такой знак в ссылку. И конечно, оно не должно совпадать там, где ему совпадать не следует. Неплохо было бы, если бы оно также форматировало текст ссылки href: протокол, домен и субдомены должны быть записаны строчными буквами. А сам текст, который будет виден на странице, должен оставаться таким, каким его ввел участник форума. Задача эта непростая и не формализуется. Критерием успешности регулярного выражения является то, как оно справляется с набором тестов, которые провоцируют его к несовпадению или совпадению не в тех местах.

Это регулярное выражение достаточно сложное и громоздкое, и мы будем создавать его по частям. Начнем с протокола.

Протокол может быть http, https и ftp. Для его обнаружения создадим строковую переменную $protocol:

my $protocol='(?:(?=[FfHh])(?i:http(?>s?)|ftp)://)';

Если в тексте следующий символ F, f, H или h, то этот подшаблон делает проверку следующих за ним символов и, если это протокол, поглощает его вместе с префиксом. Я взял весь шаблон для протокола в скобки, потому что в общем регулярном выражении у этого подшаблона может стоять квантификатор, который должен относиться ко всему этому подшаблону, а не к последнему его символу /.

Результирующий оператор подстановки у нас будет иметь модификатор x, поэтому для имени хоста запишем такое регулярное выражение в свободном формате:

my $host=<<HOST;
   (?>[A-Za-z0-9]{1,63}\\.)
        (?>[A-Za-z0-9]
             (?>[-A-Za-z0-9]{0,62})\\.
         )*
HOST

Эта запись соответствует последовательности имен, разделенных точками, или IP-адресу, она в том числе поглотит префикс www. Также учтено, что длина одного имени (от точки до точки) не может быть больше 63 символов. Обратите внимание на два обратных слэша перед точками. Подобная запись содержимого переменной (here doc) транслируется как строка в двойных кавычках. В таких строках обратный слэш является метасимволом.

Поэтому, чтобы записать его в такой строке один раз, его надо повторить дважды. Если распечатать переменную $host, то мы увидим по одному обратному слэшу перед точками.

По правде говоря, если бы мы поставили по одной обратной черте перед точками, то результат был бы тем же, потому что Perl игнорирует неизвестные эскейп-последовательности, такие, как \., т.к. точка в строках не является метасимволом, и оставляет обратную косую как она есть. Другое дело сочетания \$ и \@. Т.к. символы $ и @ в строках, ограниченных двойными кавычками, являются префиксами имен переменных, Perl перед ними удаляет обратную косую черту, которая маскирует эти метасимволы.

Для поддоменов запишем такой шаблон:

my $subdom='(?:(?>[A-Za-z0-9](?:[-A-Za-z0-9]{0,61}[A-Za-z0-9])?)\\.)+';

Здесь строка ограничена апострофами. В таких строках есть только два метасимвола - обратный слэш и апостроф. Поэтому, если мы хотим вставить в строку, ограниченную апострофами, эти символы, то их надо замаскировать обратным слэшем: \\ и \'. В результате мы вместо последовательности \\. получим во внутреннем представлении переменной $subdom последовательность \., что нам и нужно. Замечание относительно неизвестных эскейп-последовательностей для строк в двойных кавычках здесь также в силе.

< Лекция 7 || Лекция 8: 123 || Лекция 9 >
Константин Бражников
Константин Бражников
Россия
Mike .
Mike .
Россия