Пример поиска и подсветки ссылок и e-mail в тексте
Как же мы будем форматировать найденный текст? Одним оператором s///. Можно применить вариант с модификатором e, а можно обойтись без него, но тогда в выражении для замены надо будет использовать интерполяцию кода Perl в строку.
Этот оператор подстановки выглядит так:
$text =~ s!$re!<a href="${\($2 ? '' : 'http://')} \L$1\E$3" target="_blank">$1$3</a>!gx;
Регулярное выражение для поиска $re уже составлено, остается сформировать строку для замещения найденного URL. Мы не можем в этой строке замещения сделать конкатенацию вида "…".$var1."…".$var2…, потому что в нем участвует строка без символов-ограничителей строки. Поэтому уже знакомой конструкцией ${\( код Perl ) мы вставляем протокол с помощью тернарного оператора
$2 ? '' : 'http://'
Если протокол в URL был задан, то мы вставляем то, что задано, если не задан, то вставляем http://. Дальше вставляем часть URL без хвоста ($1), предварительно сделав в нем все буквы строчными. За ней идет хвост $3. А в тексте, что будет виден на HTML-странице, будет фигурировать то, что вводил пользователь: $1$3.
#!/usr/bin/perl -w use strict; my $protocol='(?:(?=[FfHh])(?i:http(?>s?)|ftp)://)'; my $host=<<HOST; (?>[A-Za-z0-9]{1,63}\\.) (?>[A-Za-z0-9] (?>[-A-Za-z0-9]{0,62})\\. )* HOST my $subdom=<<SUBDOM; (?: (?>[A-Za-z0-9] (?:[-A-Za-z0-9]{0,61}[A-Za-z0-9])? )\\. )+ SUBDOM my $wb='(?![A-Za-z0-9])'; my $zone=<<ZONE; (?i:(?(?=[a-z]{3}$wb)(?>com|net|org|edu|biz|gov|int|mil)| (?(?=[a-z]{2}$wb)[a-z]{2}| (?(?=[a-z]{4}$wb)(?>info|aero|name)| (?(?=[a-z]{6}$wb)museum|(?!) ) ) ) ) (?>\\.[a-z]{2}$wb)? ) ZONE my $port="(?::\\d{1,5}$wb)"; my $tail=<<TAIL; (?:[/?] (?>[^.,"'<>()[\\]{}\\s\\x7F-\\xFF]*) (?:(?>[.,?]+) (?:[^"'<>()[\\]{}\\s\\x7F-\\xFF]+) )* (?<![,.?!-]) ) TAIL my $re=<<RE; ( (?>($protocol)(?(2)(?>$host$zone)|$host$zone) (?![A-Za-z0-9])| (?<![A-Za-z0-9_\\\@-]) (?<!\\.(?!(?i:www))) $subdom$zone(?![A-Za-z0-9_.-]*\\\@) ) (?>(?>$port?(?>\\\@$host$zone(?![A-Za-z0-9_.-]*\\\@))?)?) ) ($tail?) RE my $text=<<TEXT; URLs: Ftp://a.com/AAa Look at:aaa.Museum. http://www.proxy.com:80\@www.site.com/ http://proxy.com:80\@site.com/ http://proxy.com\@site.com/ aAaa.com.au.rr.ggg Zwww.Yabcd.co.uk Фforum.abcd.de www.Abc.eu П123.123.123.1234.com/?q=aaa http://Abc.Tk Ahttp://www.Abc.pt/AAa http://abc.au/query/vid.cam.dig/sony.dcrhc15.htm#full_image Ф.Www.old-avto.tk NOT URLs: aaa.museumm http://aaa.museumm, http://-aaa.com www._aaa.com www.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com TEXT $text =~ s!$re!<a href="${\($2 ? '' : 'http://')}\L$1\E$3" target="_blank">$1$3</a>!gx; print $text;Листинг 8.1.
А вот текст, который она печатает:
URLs: <a href="ftp://a.com/AAa" target="_blank">Ftp://a.com/AAa</a> Look at:<a href="http://aaa.museum" target="_blank">aaa.Museum</a>. <a href="http://www.proxy.com:80@www.site.com/" target="_blank">http://www.proxy.com:80@www.site.com/</a> <a href="http://proxy.com:80@site.com/" target="_blank">http://proxy.com:80@site.com/</a> <a href="http://proxy.com@site.com/" target="_blank">http://proxy.com@site.com/</a> <a href="http://aaaa.com.au.rr" target="_blank">aAaa.com.au.rr</a>.ggg <a href="http://zwww.yabcd.co.uk" target="_blank">Zwww.Yabcd.co.uk</a> Ф<a href="http://forum.abcd.de" target="_blank">forum.abcd.de</a> <a href="http://www.abc.eu" target="_blank">www.Abc.eu</a> П<a href="http://123.123.123.1234.com/?q=aaa" target="_blank">123.123.123.1234.com/?q=aaa</a> <a href="http://abc.tk" target="_blank">http://Abc.Tk</a> A<a href="http://www.abc.pt/AAa" target="_blank">http://www.Abc.pt/AAa</a> <a href="http://abc.au/query/vid.cam.dig/sony.dcrhc15.htm#full_image" target="_blank">http://abc.au/query/vid.cam.dig/sony.dcrhc15.htm#full_image</a> Ф.<a href="http://www.old-avto.tk" target="_blank">Www.old-avto.tk</a> NOT URLs: aaa.museumm http://aaa.museumm, http://-aaa.com www._aaa.com www.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.comЛистинг 8.2.
3-я, 10-я и 13-я строка не уместились по ширине страницы.
Обратите внимание, как преобразуется в URL строка
aAaa.com.au.rr.ggg
Получается
<a href="http://aaaa.com.au.rr" target="_blank">aAaa.com.au.rr</a>.ggg
.ggg не считается частью URL. Количество последовательностей символов через точку ограничено, чтобы не захватить в URL следующий за ним текст. Это интуитивное ограничение.
8.2 Преобразование ftp, http и e-mail ссылок в теги HTML
Если в тексте могут присутствовать адреса электронной почты, то наша задача усложняется, поскольку ссылка через прокси-сервер
http://www.proxy.com:80@www.site.com/
может трактоваться неоднозначно из-за наличия в ней символа @. Если мы сначала будем искать адреса электронной почты, то программа может "найти" такой e-mail:
80@www.site.com
Конфликт также может возникнуть со ссылками вида
ftp://login:passw@a-aa.com/www/
Чтобы устранить этот конфликт, перепишем регулярные выражения для поиска URL и добавим к ним регулярное выражение для поиска e-mail. Форматировать ссылки будем несколькими операторами подстановки, т.к. для одного оператора эта задача слишком сложна.
Вот текст всей этой программы:
#!perl -w use strict; my $wb='(?![A-Za-z0-9])'; my $protocol='(?:(?=[FfHh])(?i:http(?>s?)|ftp)://)'; my $host=<<HOST; (?>[-A-Za-z0-9_]{1,63}\\.) (?>[A-Za-z0-9_] (?>[-A-Za-z0-9_]{0,62})\\. )* HOST my $subdom=<<SUBDOM; (?: (?>[A-Za-z0-9] (?:[-A-Za-z0-9]{0,61}[A-Za-z0-9])? )\\. )+ SUBDOM my $subdom1='[A-Za-z0-9](?:[-A-Za-z0-9]{0,61}[A-Za-z0-9])?'; my $zone=<<ZONE; (?i: (?=[a-z]{3}$wb) (?>com|net|org|edu|biz|gov|int|mil)| (?(?=[a-z]{2}$wb)[a-z]{2}| (?(?=[a-z]{4}$wb)(?>info|aero|name)| (?(?=[a-z]{6}$wb)museum|(?!) ) ) ) (?>\\.[a-z]{2}$wb)? ) ZONE my $port="(?::\\d{1,5}$wb)"; my $tail=<<TAIL; (?:[/?] (?>[^.,"'<>()\\[\\]{}\\s\\x7F-\\xFF]*) (?: (?>[.,?]+) (?:[^"'<>()\\[\\]{}\\s\\x7F-\\xFF]+) )* (?<![,.?!-]) ) TAIL my $firstchr='(?:[A-Za-z0-9])'; my $namechr='(?:[A-Za-z0-9_+.-])'; my $ip='(?:(?<!\\d)(?>\\d{1,3})\\.(?>\\d{1,3})\\.(?>\\d{1,3})\\.(?>\\d{1,3})(?!\\d))'; # Login и passw ограничены 32 символами my $loginpasswat='(?:(?>[A-Za-z0-9_]{1,32})(?>(?::[A-Za-z0-9_]{1,32})?)\\@)'; my $res; $_=q(http://www.proxy.com:80@www.site.com/ Ftp://a.com/AAa Ftp://Login:Passw@Www.Aaa.Com/Www/ Ftp://login:passw@a-aa.com/www/ Mailto:aaa@sss.zzz.co. Mailto:aaa@sss.zzz.eee.co. aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@aaa.com ыы@ddd.com ыы@ddЫd.com ыыsы-sf.ff.com.com@ddd.com ыыsы.-sf.ff@ddd.com Mailto:aaa@sss.co, aaa@sss.comЫЫЫ aaa.Bb.b@aaaa.com.ru.rr.ggg aaa.museumm Look at:aaa.museum. httpS://aaa.museumm, http://www.proxy.com:80@www.site.com/ http://proxy.com:80@site.com/ http://proxy.com@site.com/ aAaa.com.ru.rr.ggg Zwww.Yabcd.co.uk Фforum.abcde.ru www.Eabcd.ru http://Eabcd.Ru Ahttp://www.Eabcd.ru/AAa http://abc.ru/query/vid.cam.dig/sony.dcrhc15.htm#full_image Ф.Www.abcdefg-avto.ru httP://1.2.3.400/aaa/ddd.exe? 1.2.3.400/aaa/ddd.exe?d=c,f=t;&e=h, .0.2.3.400. http://66.123.234.555/ddd michel@ab-cdefg.ru http://99.999.999.999/search?q=cache:w5K8GsupwvcJ:olympus.flexiblesoft.com/c-4000-man.doc+c-4000-man&hl=ru& client=firefox-a); # Оформляем ссылки без login:passw s#((?>($protocol)(?(2)(?>$ip|$host$zone)|$host$zone)(?![A-Za-z0-9])|(?<![A-Za-z0-9_\@-])(?<!\.(?!(?i:www))) $subdom$zone(?![A-Za-z0-9_.-]*\@))(?>(?>$port?(?>\@$host$zone(?![A-Za-z0-9_.-]*\@))?)?))($tail?)# $res=$2 ? '' : 'http://'; qq!<a href="$res\L$1\E$3" target="_blank">$1$3</a>!#gex; # Оформляем ссылки с login:passw s#($protocol)($loginpasswat)($ip|$host$zone)((?>$port?)$tail?)#<a href=\"\L$1\E$2\L$3\E$4 \" target=\"_blank\">$1$2$3$4</a>"#gx; # Оформляем е-мейлы. Этот оператор чувствителен к тексту, на который меняет предыдущие операторы! s#((?<!$firstchr)$firstchr(?>$namechr{0,39})\@(?>$subdom1)(?:\.$subdom1)?\.$zone) (?!(?>[^\s"<]*)(?:"\starget="_blank">|</a>))#<a href="mailto:$1">$1</a>#gx; # Оформляем ссылки с IP s#((?<![>/])$ip(?>$port?))($tail?)#"<a href=\"http://\L$1\E$2\" target=\"_blank\">$1$2</a>"#gx; print $_;Листинг 8.3.
А вот результат ее работы:
<a href="http://www.proxy.com:80@www.site.com/" target="_blank">http://www.proxy.com:80@www.site.com/</a> <a href="ftp://a.com/AAa" target="_blank">Ftp://a.com/AAa</a> <a href="ftp://Login:Passw@www.aaa.com/Www/" target="_blank">Ftp://Login:Passw@Www.Aaa.Com/Www/</a>" <a href="ftp://login:passw@a-aa.com/www/" target="_blank">Ftp://login:passw@a-aa.com/www/</a>" Mailto:<a href="mailto:aaa@sss.zzz.co">aaa@sss.zzz.co</a>. Mailto:aaa@sss.zzz.eee.co. aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@aaa.com ыы@ddd.com ыы@ddЫ<a href="http://d.com" target="_blank">d.com</a> ыыsы-<a href="mailto:sf.ff.com.com@ddd.com">sf.ff.com.com@ddd.com</a> ыыsы.-<a href="mailto:sf.ff@ddd.com">sf.ff@ddd.com</a> Mailto:<a href="mailto:aaa@sss.co">aaa@sss.co</a>, <a href="mailto:aaa@sss.com">aaa@sss.com</a>ЫЫЫ <a href="mailto:aaa.Bb.b@aaaa.com.ru.rr">aaa.Bb.b@aaaa.com.ru.rr</a>.ggg aaa.museumm Look at:<a href="http://aaa.museum" target="_blank">aaa.museum</a>. httpS://aaa.museumm, <a href="http://www.proxy.com:80@www.site.com/" target="_blank">http://www.proxy.com:80@www.site.com/</a> <a href="http://proxy.com:80@site.com/" target="_blank">http://proxy.com:80@site.com/</a> <a href="http://proxy.com@site.com/" target="_blank">http://proxy.com@site.com/</a> <a href="http://aaaa.com.ru.rr" target="_blank">aAaa.com.ru.rr</a>.ggg <a href="http://zwww.yabcd.co.uk" target="_blank">Zwww.Yabcd.co.uk</a> Ф<a href="http://forum.abcde.ru" target="_blank">forum.abcde.ru</a> <a href="http://www.eabcd.ru" target="_blank">www.Eabcd.ru</a> <a href="http://eabcd.ru" target="_blank">http://Eabcd.Ru</a> A<a href="http://www.eabcd.ru/AAa" target="_blank">http://www.Eabcd.ru/AAa</a> <a href="http://abc.ru/query/vid.cam.dig/sony.dcrhc15.htm#full_image" target="_blank">http://abc.ru/query/vid.cam.dig/sony.dcrhc15.htm#full_image</a> Ф.<a href="http://www.abcdefg-avto.ru" target="_blank">Www.abcdefg-avto.ru</a> <a href="http://1.2.3.400/aaa/ddd.exe" target="_blank">httP://1.2.3.400/aaa/ddd.exe</a>? "<a href="http://1.2.3.400/aaa/ddd.exe?d=c,f=t;&e=h" target="_blank">1.2.3.400/aaa/ddd.exe?d=c,f=t;&e=h</a>", ."<a href="http://0.2.3.400" target="_blank">0.2.3.400</a>". <a href="http://66.123.234.555/ddd" target="_blank">http://66.123.234.555/ddd</a> <a href="mailto:michel@ab-cdefg.ru">michel@ab-cdefg.ru</a> <a href="http://99.999.999.999/search?q= cache:w5K8GsupwvcJ:olympus.flexiblesoft.com/c-4000-man.doc+c-4000-man &hl=ru&client=firefox-a" target="_blank">http://99.999.999.999/search? q=cache:w5K8GsupwvcJ:olympus.flexiblesoft.com/c-4000-man.doc+c-4000-man&hl=ru&client=firefox-a</a>Листинг 8.4.
Как видим, в этом тестовом тексте программа правильно отделила e-mail ссылки от остальных ссылок.