РЕЗЮМЕ
Быстрое и простое использование шаблонов на небольших, ограниченных фрагментах достаточно четко определенных фрагментов HTML. Но использовать их во всем документе, содержащем полностью общий открытый HTML-код непредсказуемых причуд, хотя теоретически это возможно, на практике слишком сложно по сравнению с использованием чужого синтаксического анализатора, который уже был написан для этой явной цели. См. Также этот ответ для более общего обсуждения использования шаблонов в XML или HTML.
Наивное решение Regex
Вы запросили решение для регулярных выражений, поэтому я предоставлю вам такое.
#!/usr/bin/perl
use 5.10.0;
use strict;
use warnings;
$/ = undef;
$_ = <DATA>; # read all input
while (m{ < \s* img [^>]* src \s* = \s* ['"]? ([^<>'"]+) }gsix) {
print "IMG SRC=$1\n";
}
while (m{ < \s* a [^>]* href \s* = \s* ['"]? ([^<>'"]+) }gsix) {
print "A HREF=$1\n";
}
while (m{ < \s* strong [^>]* > (.*?) < \s* / \s* strong \s* > }gsix) {
print "STRONG=$1\n";
}
__END__
<td class="MODULE_PRODUCTS_CELL" align="center" valign="top" height="100">
<table width="100" summary="products">
<tr>
<td align="center" height="75">
<a href="/collections.php?prod_id=50">
<img src="files/products_categories50_t.txt" border="0" alt="products" />
</a>
<br/>
</td>
</tr>
<tr>
<td align="center">
<a href="/collections.php?prod_id=50">
<strong>Buffer</strong><br />
</a>
<td>
</tr>
</table>
</td>
Эта программа при запуске выдает следующее:
IMG SRC=files/products_categories50_t.txt
A HREF=/collections.php?prod_id=50
A HREF=/collections.php?prod_id=50
STRONG=Buffer
Если вы абсолютно уверены, что он работает для конкретного образца HTML, который вам нужен, то обязательно используйте его. Заметьте несколько вещей, которые я делаю, а вы нет. Один из них не имеет дело с HTML-строкой за раз. Это практически никогда не работает.
Однако решения такого рода работают только на крайне ограниченных формах допустимого HTML. Вы можете использовать его только тогда, когда можете гарантировать, что HTML-код, с которым вы работаете, действительно выглядит так, как вы ожидаете.
Проблема в том, что он довольно часто выглядит не очень аккуратно и аккуратно. В таких ситуациях настоятельно рекомендуется использовать класс парсинга HTML. Однако, похоже, никто не показал вам код для этого. Это не очень полезно.
Решение Regex на уровне мастера
И я сам стану одним из них. Потому что я собираюсь показать вам более общее решение для того, чтобы приблизиться к тому, что я считаю вашим, но в отличие от всех, кто когда-либо писал в Stack Overflow, я собираюсь использовать регулярные выражения, чтобы сделать это, просто, чтобы показать вам что это можно сделать, но вы не не хотите делать это так:
#!/usr/bin/perl
use 5.10.0;
use strict;
use warnings;
$/ = undef;
$_ = <DATA>; # read all input
our(
$RX_SUBS,
$tag_template_rx,
$script_tag_rx,
$style_tag_rx,
$strong_tag_rx,
$a_tag_rx,
$img_tag_rx,
);
# strip stuff we aren't supposed to look at
s{ <! DOCTYPE .*? > }{}sx;
s{ <! \[ CDATA \[ .*? \]\] > }{}gsx;
s{ $style_tag_rx .*? < (?&WS) / (?&WS) style (?&WS) > }{}gsix;
s{ $script_tag_rx .*? < (?&WS) / (?&WS) script (?&WS) > }{}gsix;
s{ <!-- .*? --> }{}gsx;
while (/$img_tag_rx/g) {
my $tag = $+{TAG};
printf "IMG tag at %d: %s\n", pos(), $tag;
while ($tag =~
m{
$RX_SUBS
\b src (?&WS) = (?&WS)
(?<VALUE>
(?: (?"ed_value) | (?&unquoted_value) )
)
}gsix)
{
my $value = dequote($+{VALUE});
print "\tSRC is $value\n";
}
}
while (/$a_tag_rx/g) {
my $tag = $+{TAG};
printf "A tag at %d: %s\n", pos(), $tag;
while ($tag =~
m{
$RX_SUBS
\b href (?&WS) = (?&WS)
(?<VALUE>
(?: (?"ed_value) | (?&unquoted_value) )
)
}gsix)
{
my $value = dequote($+{VALUE});
print "\tHREF is $value\n";
}
}
while (m{
$strong_tag_rx (?&WS)
(?<BODY> .*? ) (?&WS)
< (?&WS) / (?&WS) strong (?&WS) >
}gsix)
{
my ($tag, $body) = @+{ qw< TAG BODY > };
printf "STRONG tag at %d: %s\n\tBODY=%s\n",
pos(), $+{TAG}, $+{BODY};
}
exit;
sub dequote {
my $string = shift();
$string =~ s{
^
(?<quote> ["'] )
(?<BODY>
(?: (?! \k<quote> ) . ) *
)
\k<quote>
$
}{$+{BODY}}gsx;
return $string;
}
sub load_patterns {
$RX_SUBS = qr{ (?(DEFINE)
(?<any_attribute>
\b \w+
(?&WS) = (?&WS)
(?:
(?"ed_value)
| (?&unquoted_value)
)
)
(?<unquoted_value>
(?&unwhite_chunk)
)
(?<quoted_value>
(?<quote> ["'] )
(?: (?! \k<quote> ) . ) *
\k<quote>
)
(?<unwhite_chunk>
(?:
# (?! [<>'"] )
(?! > )
\S
) +
)
(?<WS> \s * )
(?<end_tag>
(?&html_end_tag)
| (?&xhtml_end_tag)
)
(?<html_end_tag> > )
(?<xhtml_end_tag> / > )
) # end DEFINE
}six;
my $_TAG_SUBS = $RX_SUBS . q{ (?(DEFINE)
(?<attributes>
(?:
(?&WS)
(?&one_attribute)
) *
)
(?<one_attribute>
(?= (?&legal_attribute) )
(?&any_attribute)
)
(?<optional_attribute>
(?&permitted_attribute)
| (?&deprecated_attribute)
)
(?<legal_attribute>
(?: (?&required_attribute)
| (?&optional_attribute)
| (?&standard_attribute)
| (?&event_attribute)
# for LEGAL parse only, comment out next line
| (?&illegal_attribute)
)
)
(?<optional_attribute>
(?&permitted_attribute)
| (?&deprecated_attribute)
)
(?<illegal_attribute> \b \w+ \b )
(?<tag>
(?&start_tag)
(?&WS)
(?&attributes)
(?&WS)
(?&end_tag)
)
) # end DEFINE
}; # this is a q tag, not a qr
$tag_template_rx = qr{
$_TAG_SUBS
(?<TAG> (?&XXX_tag) )
(?(DEFINE)
(?<XXX_tag> (?&tag) )
(?<start_tag> < (?&WS) XXX \b )
(?<required_attribute> (*FAIL) )
(?<standard_attribute> (*FAIL) )
(?<event_attribute> (*FAIL) )
(?<permitted_attribute> (*FAIL) )
(?<deprecated_attribute> (*FAIL) )
) # end DEFINE
}six;
$script_tag_rx = qr{
$_TAG_SUBS
(?<TAG> (?&script_tag) )
(?(DEFINE)
(?<script_tag> (?&tag) )
(?<start_tag> < (?&WS) style \b )
(?<required_attribute> type )
(?<permitted_attribute>
charset
| defer
| src
| xml:space
)
(?<standard_attribute> (*FAIL) )
(?<event_attribute> (*FAIL) )
(?<deprecated_attribute> (*FAIL) )
) # end DEFINE
}six;
$style_tag_rx = qr{
$_TAG_SUBS
(?<TAG> (?&style_tag) )
(?(DEFINE)
(?<style_tag> (?&tag) )
(?<start_tag> < (?&WS) style \b )
(?<required_attribute> type )
(?<permitted_attribute> media )
(?<standard_attribute>
dir
| lang
| title
| xml:lang
)
(?<event_attribute> (*FAIL) )
(?<permitted_attribute> (*FAIL) )
(?<deprecated_attribute> (*FAIL) )
) # end define
}six;
$strong_tag_rx = qr{
$_TAG_SUBS
(?<TAG> (?&strong_tag) )
(?(DEFINE)
(?<strong_tag> (?&tag) )
(?<start_tag>
< (?&WS)
strong
\b
)
(?<standard_attribute>
class
| dir
| ltr
| id
| lang
| style
| title
| xml:lang
)
(?<event_attribute>
on click
on dbl click
on mouse down
on mouse move
on mouse out
on mouse over
on mouse up
on key down
on key press
on key up
)
(?<required_attribute> (*FAIL) )
(?<permitted_attribute> (*FAIL) )
(?<optional_attribute> (*FAIL) )
(?<deprecated_attribute> (*FAIL) )
) # end DEFINE
}six;
$a_tag_rx = qr{
$_TAG_SUBS
(?<TAG> (?&a_tag) )
(?(DEFINE)
(?<a_tag> (?&tag) )
(?<start_tag>
< (?&WS)
a
\b
)
(?<permitted_attribute>
charset
| coords
| href
| href lang
| name
| rel
| rev
| shape
| rect
| circle
| poly
| target
)
(?<standard_attribute>
access key
| class
| dir
| ltr
| id
| lang
| style
| tab index
| title
| xml:lang
)
(?<event_attribute>
on blur
| on click
| on dbl click
| on focus
| on mouse down
| on mouse move
| on mouse out
| on mouse over
| on mouse up
| on key down
| on key press
on key up
)
(?<required_attribute> (*FAIL) )
(?<deprecated_attribute> (*FAIL) )
) # end define
}xi;
$img_tag_rx = qr{
$_TAG_SUBS
(?<TAG> (?&image_tag) )
(?(DEFINE)
(?<image_tag> (?&tag) )
(?<start_tag>
< (?&WS)
img
\b
)
(?<required_attribute>
alt
| src
)
# NB: The white space in string literals
# below DOES NOT COUNT! It's just
# there for legibility.
(?<permitted_attribute>
height
| is map
| long desc
| use map
| width
)
(?<deprecated_attribute>
align
| border
| hspace
| vspace
)
(?<standard_attribute>
class
| dir
| id
| style
| title
| xml:lang
)
(?<event_attribute>
on abort
| on click
| on dbl click
| on mouse down
| on mouse out
| on key down
| on key press
| on key up
)
###########################
) # end DEFINE
}six;
}
UNITCHECK { load_patterns() }
__END__
<td class="MODULE_PRODUCTS_CELL" align="center" valign="top" height="100">
<table width="100" summary="products">
<tr>
<td align="center" height="75">
<a href="/collections.php?prod_id=50">
<img src="files/products_categories50_t.txt" border="0" alt="products" />
</a>
<br/>
</td>
</tr>
<tr>
<td align="center">
<a href="/collections.php?prod_id=50">
<strong>Buffer</strong><br />
</a>
<td>
</tr>
</table>
</td>
Эта программа при запуске выдает следующее:
IMG tag at 304: <img src="files/products_categories50_t.txt" border="0" alt="products" />
SRC is files/products_categories50_t.txt
A tag at 214: <a href="/collections.php?prod_id=50">
HREF is /collections.php?prod_id=50
A tag at 451: <a href="/collections.php?prod_id=50">
HREF is /collections.php?prod_id=50
STRONG tag at 491: <strong>
BODY=Buffer
Выбор за вами - или Это Это?
И те, и другие решают вашу проблему с помощью регулярных выражений. возможно , что вы сможете использовать первый из двух моих подходов. Я не могу сказать, потому что, как и, казалось бы, все такие вопросы, задаваемые здесь, вы недостаточно рассказали нам о данных, чтобы мы (и, возможно, также вы) знали наверняка, будет ли достаточно наивного подхода.
Если это не так, у вас есть два варианта.
- Вы можете использовать более надежный и гибкий подход, предложенный моей второй техникой. Просто убедитесь, что вы понимаете это во всех его аспектах, потому что иначе вы не сможете поддерживать свой код - и никто другой не будет.
- Использовать класс парсинга HTML.
Я считаю маловероятным, что даже 1 человек из 1000 разумно сделал бы первый из этих двух вариантов. В частности, мне крайне неприятно, что кто-то, кто обращается за помощью в регулярных выражениях, таких же простых, как те, что в моем первом решении, будет человеком, способным управлять регулярными выражениями, указанными в моем втором решении.
Что действительно оставляет вам только один «выбор» - если я могу так свободно использовать это слово.