/g);
> Смотри также -------------------------------
Документация по модулям LWP::Simple, HTML::LinkExtor и HTML::Entities;
рецепт 20.1.
Проблема
Требуется преобразовать ASCII-текст в HTML.
Решение
Воспользуйтесь простым кодирующим фильтром из примера 20.3.
Пример 20.3. text2html
#!/usr/bin/pecl -w -p00
# text2html - простейшее html-кодирование обычного текста
# -p означает, что сценарий применяется для каждой записи.
# -00 означает, что запись представляет собой абзац
use HTML: '.Entities;
$_ = encode_entities($_, "\200-\377");
if (/"W) {
# Абзацы, начинающиеся с пропусков, заключаются в PRE> s{(.*)$}
{PRE>\n$1/PRE>\n}s; # Оставить отступы
} else {
s{"(>.*)} {$1BR>}gm; # quoted text
s{} {A HREF="$1">$K/A>}gs # Внутренние URL(xopoшo)
s{(http:\S+)} {A HREF="$1">$K/A>}gs; # Предполагаемые URL(nлoxo)
s{\*(\S+)\*} {STRONG>$K/STRONG>}g; # *Полужирный*
s{\b_(\S+)\_\b} {EM>$K/EM>}g; # Курсив.
s{^} {P>\n}; # Добавить тег абзаца
}
Комментарий
Задача преобразования произвольного текста в формат HTML не имеет общего решения, поскольку существует много разных, конфликтующих друг с другом способов форматирования обычного текста. Чем больше вам известно о входных данных, тем лучше вы их отформатируете.
Например, если вы знаете, что исходным текстом будет почтовое сообщение, можно добавить следующий блок для форматирования почтовых заголовков:
BEGIN {
print "<TABLE>";
$_ = encode_entities(scalar о);
s/\n\s+/ /g; # Строки продолжения
while ( /"(\S+?:)\s*(.*)$/gm ) { # Анализ заголовков
print "<TR><<TH ALIGN='LEFT'>$K</TH><TD>$2</TD></TR>\n";
}
print "</TABLE>HR>";
}
> Смотри также -------------------------------
Документация по модулю HTML::Entities от CPAN.
Проблема
Требуется преобразовать HTML-файл в отформатированный ASCII-текст.
Решение
Если у вас есть внешняя программа форматирования (например, lynx), воспользуйтесь ей:
$ascii = 'lynx -dump $filename';
Если вы хотите сделать все в своей программе и не беспокоитесь о том, что HTML::TreeBuilder еще не умеет обрабатывать таблицы и фреймы:
use HTML::FormatText;
use HTML::Parse;
$html = parse_htmlfile($filename);
Sformatter = HTML: :FormatText->new(leftrnargin => 0, rightmargin => 50);
$ascii = $1:ormatter->format($html);
Комментарий
В обоих примерах предполагается, что HTML-текст находится в файле. Если он хранится в переменной, то для применения lynx необходимо записать его в файл. При работе с HTML::FormatText воспользуйтесь модулем HTML::TreeBuilder:
use HTML::TreeBuilder;
use HTML::FormatText;
$html = HTML::TreeBuilder->new();
$html->parse($document);
$formatter = HTML::FormatText->new(leftmargin => 0, rightmargin o=> 50);
$ascii = $formatter->format($html);
Если вы используете Netscape, команда Save As с типом Text отлично справляется с таблицами.
> Смотри также -------------------------------
Документация по модулям HTML::Parse, HTML::TreeBuilder и HTML::Format-Text; man-страница lynx{1) вашей системы; рецепт 20.6.
Проблема
Требуется удалить из строки теги HTML и оставить в ней обычный текст.
Решение
Следующее решение встречается часто, но работает неверно (за исключением простейшего HTML-кода):
($plain_text = $html_text) ^~ s/<[~>]*>//gs; #НЕВЕРНО
Правильный, но медленный и более сложный способ связан с применением модуля LWP:
use HTML::Parse;
use HTML::FormatText;
$plain_text = HTML::FormatText->new->format(parse_html($html_text));
Комментарий
Как всегда, поставленную задачу можно решить несколькими способами. Каждое решение пытается соблюдать баланс между скоростью и универсальностью. Для простейшего HTML-кода работает даже самая элементарная командная строка:
% perl -pe "s/<[">]*>//g" ФАЙЛ
Однако это решение не подходит для файлов, в которых теги пересекают границы строк:
IMG SRC = "foo.gif" ALT = "Flurp!">
Поэтому иногда встречается следующее решение:
% perl -0777 -ре "s/<[">]*>//gs" ФАЙЛ
или его сценарный эквивалент:
{
local $/; # Временный режим чтения всего файла
$html = ;
$html =~ s/<[">]*>//gs:
}
Но даже этот вариант работает лишь для самого примитивного HTML-кода, не содержащего никаких "изюминок". В частности, он пасует перед следующими примерами допустимого HTML-кода (не говоря о многих других):
IMG SRC = "foo.gif" ALT = "А > В"> -> script if (a< b && a=c) /script> <# Просто данные #>
Проблемы возникают и в том случае, если комментарии HTML содержат другие теги:
В>Меня не видно!В> ->
Единственное надежное решение - использовать алгоритмы анализа HTML-кода из LWP. Эта методика продемонстрирована во втором фрагменте, приведенном в решении.
Чтобы сделать анализ более гибким, субклассируйте HTML::Parser от LWP и записывайте только найденные текстовые элементы:
package MyParser;
use HTML::Parser;
use HTML::Entities qw(decode_entities);
@ISA = qw(HTML::Parser):
sub text {
my($self, $text) = @_;
print decode_entities($text);
}
package main;
MyParser->new->parse_file(*F);
Если вас интересуют лишь простые теги, не содержащие вложенных тегов, возможно, вам подойдет другое решение. Следующий пример извлекает название несложного HTML-документа:
($title) = ($html =~ m#\s*(.*?)\s*
#is);
Как говорилось выше, подход с регулярными выражениями имеет свои недостатки. В примере 20.4 показано более полное решение, в котором HTML-код обрабатывается с использованием LWP.
Пример 20.4. htitle
#!/usr/bin/perl
# htitle - Получить название HTML-документа для URL
die "usage: $0 ucl ...\n" unless @
require LWP;
foreach $url (@ARGV) {
$ua = LWP::UserAgent->new();
$res = $ua->request(HTTP::Request->new(GET => $url));
print "$url: " if OARGV > 1;
if ($res->is_success) {
print $res->title, "\n";
} else {
print $res->status_line, "\n";
}
}
Приведем пример вывода:
% htitle http://www.ora.com www.oreilly.com - Welcome to O'Reilly & Associates!
% htitle http://www.perl.com/ http://www.perl.com/nullvoid http://www.perl.com/: The
www.perl.com Home Page http://www.perl.com/nullvoid: 404 File Not Found
Смотри также: Документация по модулям HTML::TreeBuilder, HTML::Parser, HTML::Entities и LWP::UserAgent с CPAN; рецепт 20.5.
Проблема
Требуется узнать, содержит ли документ устаревшие ссылки.
Решение
Воспользуйтесь методикой, описанной в рецепте 20.3, для получения всех ссылок я проверьте их существование функцией head модуля LWP::Simple.
Комментарий
Следующая программа является прикладным примером методики извлечения ссылок из HTML-документа. На этот раз мы не ограничиваемся простым выводом ссылок и вызываем для нее функцию head модуля LWP::Simple. Метод HEAD получает метаданные удаленного документа и определяет его статус, не загружая самого документа. Если вызов закончился неудачно, значит, ссылка не работает, и мы выводим соответствующее сообщение.
Поскольку программа использует функцию get из LWP::Simple, она должна получать URL, а не имя файла. Если вы хотите поддерживать обе возможности, воспользуйтесь модулем URI::Heuristic (см. рецепт 20.1).
Пример 20.5. churl
#!/usr/bin/perl -w
# churl - проверка URL
use HTML::LinkExtor;
use LWP::Simple qw(get head);
$base_url = shift
or die "usage: $0 \n";
Sparser = HTML::LinkExtor->new(undef, $base_url);
$parser->parse(get($base_url));
@links = $parser->links;
print "$base_url: \n";
foreach $linkarray (@>links) { my @element = @$linkarray;
my $elt_type = shift @element;
while (@element) {
my ($attr_name , $attr_value) = splice(@element, 0, 2);
if ($attr_value->scheme =~ /\b(ftp|https?|file)\b/) {
print " $attr_value: ", head($attr_value)? "OK" : "BAD", "\n";
}
} }
Для программы действуют те же ограничения, что и для программы, использующей HTML::LinkExtor, из рецепта 20.3.
> Смотри также -------------------------------
Документация по модулям HTML::LinkExtor, LWP::Simple, LWP::UserAgent и HTTP::Response с CPAN; рецепт 20.8.