Опубликован: 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 >

Как же мы будем форматировать найденный текст? Одним оператором 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 ссылки от остальных ссылок.

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