What to do Regular expression pattern doesn't match anywhere in string?
Я пытаюсь соответствовать <input>
введите "скрытые" поля, используя этот шаблон:
/<input type="hidden" name="([^"]*?)" value="([^"]*?)" />/
Это пример формы данных:
<input type="hidden" name="SaveRequired" value="False" /><input type="hidden" name="__VIEWSTATE1" value="1H4sIAAtzrkX7QfL5VEGj6nGi+nP" /><input type="hidden" name="__VIEWSTATE2" value="0351118MK" /><input type="hidden" name="__VIEWSTATE3" value="ZVVV91yjY" /><input type="hidden" name="__VIEWSTATE0" value="3" /><input type="hidden" name="__VIEWSTATE" value="" /><input type="hidden" name="__VIEWSTATE" value="" />
Но я не уверен, что type
, name
, а также value
атрибуты всегда будут отображаться в одном и том же порядке. Если type
Атрибут идет последним, совпадение будет неудачным, потому что в моем паттерне оно находится в начале.
Вопрос:
Как я могу изменить свой шаблон, чтобы он соответствовал независимо от положения атрибутов в <input>
тег?
PS: Кстати, я использую RegEx Desktop Tool на основеAdobe Air для тестирования регулярных выражений.
8 ответов
Вопреки всем ответам здесь, для того, что вы пытаетесь сделать, регулярное выражение является вполне допустимым решением. Это потому, что вы НЕ пытаетесь сопоставить сбалансированные теги - это было бы невозможно с регулярным выражением! Но вы сопоставляете только то, что в одном теге, и это совершенно правильно.
Здесь проблема, однако. Вы не можете сделать это с помощью одного регулярного выражения... вам нужно сделать один матч, чтобы захватить <input>
тег, затем выполните дальнейшую обработку на этом. Обратите внимание, что это будет работать, только если ни одно из значений атрибута не имеет >
характер в них, поэтому он не идеален, но его должно хватить для вменяемых входов.
Вот некоторый Perl (псевдо) код, чтобы показать вам, что я имею в виду:
my $html = readLargeInputFile();
my @input_tags = $html =~ m/
(
<input # Starts with "<input"
(?=[^>]*?type="hidden") # Use lookahead to make sure that type="hidden"
[^>]+ # Grab the rest of the tag...
\/> # ...except for the />, which is grabbed here
)/xgm;
# Now each member of @input_tags is something like <input type="hidden" name="SaveRequired" value="False" />
foreach my $input_tag (@input_tags)
{
my $hash_ref = {};
# Now extract each of the fields one at a time.
($hash_ref->{"name"}) = $input_tag =~ /name="([^"]*)"/;
($hash_ref->{"value"}) = $input_tag =~ /value="([^"]*)"/;
# Put $hash_ref in a list or something, or otherwise process it
}
Основной принцип здесь - не пытайтесь делать слишком много с одним регулярным выражением. Как вы заметили, регулярные выражения обеспечивают определенный порядок. Вместо этого вам нужно сначала сопоставить КОНТЕКСТ того, что вы пытаетесь извлечь, а затем выполнить сопоставление с данными, которые вы хотите.
РЕДАКТИРОВАТЬ: Тем не менее, я согласен, что в целом, использование синтаксического анализатора HTML, вероятно, проще и лучше, и вы действительно должны подумать о редизайне вашего кода или пересмотре ваших целей.:-) Но я должен был опубликовать этот ответ в качестве противодействия реакции коленного рефлекса, что парсинг любого подмножества HTML невозможен: HTML и XML нерегулярны, когда вы рассматриваете всю спецификацию, но спецификация тега прилично регулярна Конечно, во власти PCRE.
О да, вы можете использовать регулярные выражения для анализа HTML!
Для задачи, которую вы пытаетесь, регулярные выражения идеально подходят!
Это правда, что большинство людей недооценивают сложность парсинга HTML с помощью регулярных выражений и поэтому делают это плохо.
Но это не какой-то фундаментальный недостаток, связанный с вычислительной теорией. Эта глупость много попугаев здесь, но вы не верите им.
Поэтому, хотя это, безусловно, можно сделать (эта публикация служит доказательством существования этого неопровержимого факта), это не означает, что так идолжно быть.
Вы должны решить для себя, подходит ли вам задача написания того, что составляет выделенный специализированный HTML-анализатор из регулярных выражений. Большинство людей нет.
Ноя есть. ☻
Общие решения для парсинга HTML на основе регулярных выражений
Сначала я покажу, как легко анализироватьпроизвольный HTML с помощью регулярных выражений. Полная программа находится в конце этой публикации, но сердце парсера:
for (;;) {
given ($html) {
last when (pos || 0) >= length;
printf "\@%d=", (pos || 0);
print "doctype " when / \G (?&doctype) $RX_SUBS /xgc;
print "cdata " when / \G (?&cdata) $RX_SUBS /xgc;
print "xml " when / \G (?&xml) $RX_SUBS /xgc;
print "xhook " when / \G (?&xhook) $RX_SUBS /xgc;
print "script " when / \G (?&script) $RX_SUBS /xgc;
print "style " when / \G (?&style) $RX_SUBS /xgc;
print "comment " when / \G (?&comment) $RX_SUBS /xgc;
print "tag " when / \G (?&tag) $RX_SUBS /xgc;
print "untag " when / \G (?&untag) $RX_SUBS /xgc;
print "nasty " when / \G (?&nasty) $RX_SUBS /xgc;
print "text " when / \G (?&nontag) $RX_SUBS /xgc;
default {
die "UNCLASSIFIED: " .
substr($_, pos || 0, (length > 65) ? 65 : length);
}
}
}
Видите, как легко это читать?
Как написано, он идентифицирует каждый фрагмент HTML и сообщает, где он нашел этот фрагмент. Вы можете легко изменить его, чтобы сделать все, что вы хотите с любым данным типом или для более конкретных типов, чем эти.
У меня нет неудачных тестовых случаев (слева:): я успешно запустил этот код на более чем 100 000 HTML-файлов - каждый из которых я мог быстро и легко достать. Помимо этого, я также запускаю его на файлах, специально созданных, чтобы сломать наивные парсеры.
Это не наивный парсер.
О, я уверен, что это не идеально, но мне пока не удалось сломать это. Я полагаю, что даже если бы что-то и было, исправить это было бы легко из-за четкой структуры программы. Даже регулярные программы должны иметь структуру.
Теперь, когда это не так, позвольте мне ответить на вопрос ОП.
Демонстрация решения задачи ОП с помощью регулярных выражений
Немногоhtml_input_rx
Программа, которую я включил ниже, производит следующий вывод, так что вы можете видеть, что синтаксический анализ HTML с регулярными выражениями прекрасно работает для того, что вы хотите сделать:
% html_input_rx Amazon.com-_Online_Shopping_for_Electronics,_Apparel,_Computers,_Books,_DVDs_\&_more.htm
input tag #1 at character 9955:
class => "searchSelect"
id => "twotabsearchtextbox"
name => "field-keywords"
size => "50"
style => "width:100%; background-color: #FFF;"
title => "Search for"
type => "text"
value => ""
input tag #2 at character 10335:
alt => "Go"
src => "http://g-ecx.images-amazon.com/images/G/01/x-locale/common/transparent-pixel._V192234675_.gif"
type => "image"
Разбор входных тегов, не вижу злого ввода
Вот источник для программы, которая произвела вывод выше.
#!/usr/bin/env perl
#
# html_input_rx - pull out all <input> tags from (X)HTML src
# via simple regex processing
#
# Tom Christiansen <tchrist@perl.com>
# Sat Nov 20 10:17:31 MST 2010
#
################################################################
use 5.012;
use strict;
use autodie;
use warnings FATAL => "all";
use subs qw{
see_no_evil
parse_input_tags
input descape dequote
load_patterns
};
use open ":std",
IN => ":bytes",
OUT => ":utf8";
use Encode qw< encode decode >;
###########################################################
parse_input_tags
see_no_evil
input
###########################################################
until eof(); sub parse_input_tags {
my $_ = shift();
our($Input_Tag_Rx, $Pull_Attr_Rx);
my $count = 0;
while (/$Input_Tag_Rx/pig) {
my $input_tag = $+{TAG};
my $place = pos() - length ${^MATCH};
printf "input tag #%d at character %d:\n", ++$count, $place;
my %attr = ();
while ($input_tag =~ /$Pull_Attr_Rx/g) {
my ($name, $value) = @+{ qw< NAME VALUE > };
$value = dequote($value);
if (exists $attr{$name}) {
printf "Discarding dup attr value '%s' on %s attr\n",
$attr{$name} // "<undef>", $name;
}
$attr{$name} = $value;
}
for my $name (sort keys %attr) {
printf " %10s => ", $name;
my $value = descape $attr{$name};
my @Q; given ($value) {
@Q = qw[ " " ] when !/'/ && !/"/;
@Q = qw[ " " ] when /'/ && !/"/;
@Q = qw[ ' ' ] when !/'/ && /"/;
@Q = qw[ q( ) ] when /'/ && /"/;
default { die "NOTREACHED" }
}
say $Q[0], $value, $Q[1];
}
print "\n";
}
}
sub dequote {
my $_ = $_[0];
s{
(?<quote> ["'] )
(?<BODY>
(?s: (?! \k<quote> ) . ) *
)
\k<quote>
}{$+{BODY}}six;
return $_;
}
sub descape {
my $string = $_[0];
for my $_ ($string) {
s{
(?<! % )
% ( \p{Hex_Digit} {2} )
}{
chr hex $1;
}gsex;
s{
& \043
( [0-9]+ )
(?: ;
| (?= [^0-9] )
)
}{
chr $1;
}gsex;
s{
& \043 x
( \p{ASCII_HexDigit} + )
(?: ;
| (?= \P{ASCII_HexDigit} )
)
}{
chr hex $1;
}gsex;
}
return $string;
}
sub input {
our ($RX_SUBS, $Meta_Tag_Rx);
my $_ = do { local $/; <> };
my $encoding = "iso-8859-1"; # web default; wish we had the HTTP headers :(
while (/$Meta_Tag_Rx/gi) {
my $meta = $+{META};
next unless $meta =~ m{ $RX_SUBS
(?= http-equiv )
(?&name)
(?&equals)
(?= (?"e)? content-type )
(?&value)
}six;
next unless $meta =~ m{ $RX_SUBS
(?= content ) (?&name)
(?&equals)
(?<CONTENT> (?&value) )
}six;
next unless $+{CONTENT} =~ m{ $RX_SUBS
(?= charset ) (?&name)
(?&equals)
(?<CHARSET> (?&value) )
}six;
if (lc $encoding ne lc $+{CHARSET}) {
say "[RESETTING ENCODING $encoding => $+{CHARSET}]";
$encoding = $+{CHARSET};
}
}
return decode($encoding, $_);
}
sub see_no_evil {
my $_ = shift();
s{ <! DOCTYPE .*? > }{}sx;
s{ <! \[ CDATA \[ .*? \]\] > }{}gsx;
s{ <script> .*? </script> }{}gsix;
s{ <!-- .*? --> }{}gsx;
return $_;
}
sub load_patterns {
our $RX_SUBS = qr{ (?(DEFINE)
(?<nv_pair> (?&name) (?&equals) (?&value) )
(?<name> \b (?= \pL ) [\w\-] + (?<= \pL ) \b )
(?<equals> (?&might_white) = (?&might_white) )
(?<value> (?"ed_value) | (?&unquoted_value) )
(?<unwhite_chunk> (?: (?! > ) \S ) + )
(?<unquoted_value> [\w\-] * )
(?<might_white> \s * )
(?<quoted_value>
(?<quote> ["'] )
(?: (?! \k<quote> ) . ) *
\k<quote>
)
(?<start_tag> < (?&might_white) )
(?<end_tag>
(?&might_white)
(?: (?&html_end_tag)
| (?&xhtml_end_tag)
)
)
(?<html_end_tag> > )
(?<xhtml_end_tag> / > )
) }six;
our $Meta_Tag_Rx = qr{ $RX_SUBS
(?<META>
(?&start_tag) meta \b
(?:
(?&might_white) (?&nv_pair)
) +
(?&end_tag)
)
}six;
our $Pull_Attr_Rx = qr{ $RX_SUBS
(?<NAME> (?&name) )
(?&equals)
(?<VALUE> (?&value) )
}six;
our $Input_Tag_Rx = qr{ $RX_SUBS
(?<TAG> (?&input_tag) )
(?(DEFINE)
(?<input_tag>
(?&start_tag)
input
(?&might_white)
(?&attributes)
(?&might_white)
(?&end_tag)
)
(?<attributes>
(?:
(?&might_white)
(?&one_attribute)
) *
)
(?<one_attribute>
\b
(?&legal_attribute)
(?&might_white) = (?&might_white)
(?:
(?"ed_value)
| (?&unquoted_value)
)
)
(?<legal_attribute>
(?: (?&optional_attribute)
| (?&standard_attribute)
| (?&event_attribute)
# for LEGAL parse only, comment out next line
| (?&illegal_attribute)
)
)
(?<illegal_attribute> (?&name) )
(?<required_attribute> (?#no required attributes) )
(?<optional_attribute>
(?&permitted_attribute)
| (?&deprecated_attribute)
)
# NB: The white space in string literals
# below DOES NOT COUNT! It's just
# there for legibility.
(?<permitted_attribute>
accept
| alt
| bottom
| check box
| checked
| disabled
| file
| hidden
| image
| max length
| middle
| name
| password
| radio
| read only
| reset
| right
| size
| src
| submit
| text
| top
| type
| value
)
(?<deprecated_attribute>
align
)
(?<standard_attribute>
access key
| class
| dir
| ltr
| id
| lang
| style
| tab index
| title
| xml:lang
)
(?<event_attribute>
on blur
| on change
| 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
| on select
)
)
}six;
}
UNITCHECK {
load_patterns();
}
END {
close(STDOUT)
|| die "can't close stdout: $!";
}
Там вы идете! Ничего подобного!:)
Тольковы можете судить, соответствует ли ваш навык регулярным выражениям какой-либо конкретной задаче анализа. У каждого уровень мастерства разный, и каждое новое задание разное. Для заданий, где у вас есть четко определенный входной набор, регулярные выражения, очевидно, являются правильным выбором, потому что их легко собрать, когда у вас есть ограниченное подмножество HTML для работы. Даже начинающие регулярные выражения должны справляться с этими заданиями с помощью регулярных выражений. Все остальное излишне.
Однако, как только HTML начинает становиться все менее понятным, как только он начинает разветвляться способами, которые вы не можете предсказать, но которые совершенно законны, как только вам придется сопоставлять более разные виды вещей или с более сложными зависимостями, вы в конечном итоге достигнете точки, где чтобы создать решение, использующее регулярные выражения, вы должны работать усерднее, чем при использовании класса синтаксического анализа. То, где эта точка безубыточности падает, снова зависит от вашего собственного уровня комфорта с регулярными выражениями.
И что же мне делать?
Я не собираюсь рассказывать вам, что вы должны сделать или что вы не можете сделать. Я думаю, что это неправильно. Я просто хочу представить вам возможности, немного откройте глаза. Вы можете выбрать, что вы хотите сделать и как вы хотите это сделать. Абсолютов нет - и никто другой не знает вашей ситуации так же хорошо, как вы сами. Если что-то кажется слишком большим, ну, может быть, так и есть. Знаете, программирование должно бытьвеселым. Если это не так, вы можете делать это неправильно.
Можно посмотреть на мойhtml_input_rx
Программа любым количеством действительных способов. Одним из них является то, что вы действительно можете анализировать HTML с помощью регулярных выражений. Но другое заключается в том, что это намного, намного, намного сложнее, чем кто-либо когда-либо думал. Это может легко привести к выводу, что моя программа является свидетельством того, что вы не должны делать, потому что это действительно слишком сложно.
Я не буду с этим не согласен. Конечно, если все, что я делаю в своей программе, не имеет смысла для вас после некоторого изучения, то вам не следует пытаться использовать регулярные выражения для такого рода задач. Для конкретного HTML регулярные выражения хороши, но для общего HTML они равносильны безумию. Я все время использую классы парсинга, особенно если это HTML, который я сам не генерировал.
Регулярные выражения, оптимальные длянебольших задач разбора HTML, пессимальные для больших
Даже если моя программа воспринимается как иллюстрация того, почему вы не должны использовать регулярные выражения для анализа общего HTML-кода - это нормально, потому что я вроде бы хотел, чтобы это было так - - это все равно должно быть откровением, чтобы больше людей ломали ужасно распространенные и неприятная, неприятная привычка писать нечитаемые, неструктурированные и не поддерживаемые шаблоны.
Шаблоны не должны быть безобразными, и они не должны быть жесткими. Если вы создаете уродливые узоры, это отражение вас, а не их.
Феноменально изысканный язык регулярных выражений
Меня попросили указать, что мое предложенное решение вашей проблемы было написано на Perl. Вы удивлены? Вы не заметили? Является ли это откровение бомбой?
Я должен признаться, что нахожу этот запрос ввысшей степени странным, поскольку у любого, кто не может понять это, глядя на самую первую строчку моей программы, наверняка есть и другие умственные отклонения.
Это правда, что не все другие инструменты и языки программирования являются такими же удобными, выразительными и мощными, когда речь идет о регулярных выражениях, как Perl. Там есть большой спектр, с некоторыми, более подходящими чем другие. В целом, с языками, в которых регулярные выражения выражены как часть основного языка, а не как библиотека, легче работать. Я ничего не сделал с регулярными выражениями, которые вы не могли бы сделать, скажем, в PCRE, хотя вы бы по-другому структурировали программу, если бы использовали C.
В конце концов, другие языки будут догонять то, где сейчас находится Perl с точки зрения регулярных выражений. Я говорю это потому, что когда Perl начинал, никто не имел ничего подобного регулярным выражениям Perl. Скажите что угодно, но именно здесь Perl явно выиграл: все копировали регулярные выражения Perl, хотя и на разных этапах своего развития. Perl впервые применил почти (не совсем все, но почти) все, на что вы сегодня полагаетесь в современных моделях, независимо от того, какой инструмент или язык вы используете. Так что в конце концов остальные догонят.
Но они поймут только то, где Perl был когда-то в прошлом, как сейчас. Все продвигается. В регулярных выражениях, если ничего другого, куда ведет Perl, следуют другие. Где будет Perl, когда все наконец поймут, где сейчас находится Perl? Понятия не имею, но знаю, что мы тоже переедем. Возможно, мы будем ближе к стилю крафта Perl Per.
Если вам нравятся такие вещи, но вы хотели бы использовать их в Perl₅, вам может быть интересен замечательный модуль Дамиана Конвея Regexp::Grammars. Это совершенно потрясающе, и делает то, что я сделал здесь, в моей программе, таким же примитивным, как и мое, делает шаблоны, которые люди собирают вместе, без пробелов и буквенных идентификаторов. Проверьте это!
Простой HTML Chunker
Вот полный исходный код парсера, с которого я показал центральную часть в начале этой публикации.
Я не предлагаю, чтобы вы использовали это в строго проверенном классе разбора. Но я устал от людей, притворяющихся, что никто не может анализировать HTML с регулярными выражениями только потому, что они не могут. Вы можете ясно, и эта программа является доказательством этого утверждения.
Конечно, это не легко, новозможно!
И попытка сделать это - ужасная трата времени, потому что существуют хорошие классы разбора, которые вы должны использовать для этой задачи. Правильный ответ для людей, пытающихся разобрать произвольный HTML, не в том, что это невозможно. Это простой и неискренний ответ. Правильный и честный ответ заключается в том, что они не должны пытаться делать это, потому что слишком сложно беспокоиться об этом с нуля; они не должны ломать спину, стремясь заново изобрести колесо, которое работает отлично.
С другой стороны, HTML, который входит в предсказуемое подмножество, очень легко анализировать с помощью регулярных выражений. Неудивительно, что люди пытаются использовать их, потому что для небольших проблем, игрушечных проблем, возможно, нет ничего проще. Вот почему так важно различать две задачи - специфическую и общую - поскольку они не обязательно требуют одинакового подхода.
Я надеюсь в будущем увидеть более справедливую и честную обработку вопросов о HTML и регулярных выражениях.
Вот мой HTML-лексер. Он не пытается выполнить проверочный анализ; это только идентифицирует лексические элементы. Вы можете думать об этом больше как о чанкере HTML, чем как о парсере HTML. Это не очень прощающий битый HTML, хотя он делает некоторые небольшие поправки в этом направлении.
Даже если вы никогда не разбираете полный HTML самостоятельно (а зачем вам это решаемая проблема!), В этой программе есть много интересных фрагментов регулярных выражений, из которых, я полагаю, многие люди могут многому научиться. Наслаждайтесь!
#!/usr/bin/env perl
#
# chunk_HTML - a regex-based HTML chunker
#
# Tom Christiansen <tchrist@perl.com
# Sun Nov 21 19:16:02 MST 2010
########################################
use 5.012;
use strict;
use autodie;
use warnings qw< FATAL all >;
use open qw< IN :bytes OUT :utf8 :std >;
MAIN: {
$| = 1;
lex_html(my $page = slurpy());
exit();
}
########################################################################
sub lex_html {
our $RX_SUBS; ###############
my $html = shift(); # Am I... #
for (;;) { # forgiven? :)#
given ($html) { ###############
last when (pos || 0) >= length;
printf "\@%d=", (pos || 0);
print "doctype " when / \G (?&doctype) $RX_SUBS /xgc;
print "cdata " when / \G (?&cdata) $RX_SUBS /xgc;
print "xml " when / \G (?&xml) $RX_SUBS /xgc;
print "xhook " when / \G (?&xhook) $RX_SUBS /xgc;
print "script " when / \G (?&script) $RX_SUBS /xgc;
print "style " when / \G (?&style) $RX_SUBS /xgc;
print "comment " when / \G (?&comment) $RX_SUBS /xgc;
print "tag " when / \G (?&tag) $RX_SUBS /xgc;
print "untag " when / \G (?&untag) $RX_SUBS /xgc;
print "nasty " when / \G (?&nasty) $RX_SUBS /xgc;
print "text " when / \G (?&nontag) $RX_SUBS /xgc;
default {
die "UNCLASSIFIED: " .
substr($_, pos || 0, (length > 65) ? 65 : length);
}
}
}
say ".";
}
#####################
# Return correctly decoded contents of next complete
# file slurped in from the <ARGV> stream.
#
sub slurpy {
our ($RX_SUBS, $Meta_Tag_Rx);
my $_ = do { local $/; <ARGV> }; # read all input
return unless length;
use Encode qw< decode >;
my $bom = "";
given ($_) {
$bom = "UTF-32LE" when / ^ \xFf \xFe \0 \0 /x; # LE
$bom = "UTF-32BE" when / ^ \0 \0 \xFe \xFf /x; # BE
$bom = "UTF-16LE" when / ^ \xFf \xFe /x; # le
$bom = "UTF-16BE" when / ^ \xFe \xFf /x; # be
$bom = "UTF-8" when / ^ \xEF \xBB \xBF /x; # st00pid
}
if ($bom) {
say "[BOM $bom]";
s/^...// if $bom eq "UTF-8"; # st00pid
# Must use UTF-(16|32) w/o -[BL]E to strip BOM.
$bom =~ s/-[LB]E//;
return decode($bom, $_);
# if BOM found, don't fall through to look
# for embedded encoding spec
}
# Latin1 is web default if not otherwise specified.
# No way to do this correctly if it was overridden
# in the HTTP header, since we assume stream contains
# HTML only, not also the HTTP header.
my $encoding = "iso-8859-1";
while (/ (?&xml) $RX_SUBS /pgx) {
my $xml = ${^MATCH};
next unless $xml =~ m{ $RX_SUBS
(?= encoding ) (?&name)
(?&equals)
(?"e) ?
(?<ENCODING> (?&value) )
}sx;
if (lc $encoding ne lc $+{ENCODING}) {
say "[XML ENCODING $encoding => $+{ENCODING}]";
$encoding = $+{ENCODING};
}
}
while (/$Meta_Tag_Rx/gi) {
my $meta = $+{META};
next unless $meta =~ m{ $RX_SUBS
(?= http-equiv ) (?&name)
(?&equals)
(?= (?"e)? content-type )
(?&value)
}six;
next unless $meta =~ m{ $RX_SUBS
(?= content ) (?&name)
(?&equals)
(?<CONTENT> (?&value) )
}six;
next unless $+{CONTENT} =~ m{ $RX_SUBS
(?= charset ) (?&name)
(?&equals)
(?<CHARSET> (?&value) )
}six;
if (lc $encoding ne lc $+{CHARSET}) {
say "[HTTP-EQUIV ENCODING $encoding => $+{CHARSET}]";
$encoding = $+{CHARSET};
}
}
return decode($encoding, $_);
}
########################################################################
# Make sure to this function is called
# as soon as source unit has been compiled.
UNITCHECK { load_rxsubs() }
# useful regex subroutines for HTML parsing
sub load_rxsubs {
our $RX_SUBS = qr{
(?(DEFINE)
(?<WS> \s * )
(?<any_nv_pair> (?&name) (?&equals) (?&value) )
(?<name> \b (?= \pL ) [\w:\-] + \b )
(?<equals> (?&WS) = (?&WS) )
(?<value> (?"ed_value) | (?&unquoted_value) )
(?<unwhite_chunk> (?: (?! > ) \S ) + )
(?<unquoted_value> [\w:\-] * )
(?<any_quote> ["'] )
(?<quoted_value>
(?<quote> (?&any_quote) )
(?: (?! \k<quote> ) . ) *
\k<quote>
)
(?<start_tag> < (?&WS) )
(?<html_end_tag> > )
(?<xhtml_end_tag> / > )
(?<end_tag>
(?&WS)
(?: (?&html_end_tag)
| (?&xhtml_end_tag) )
)
(?<tag>
(?&start_tag)
(?&name)
(?:
(?&WS)
(?&any_nv_pair)
) *
(?&end_tag)
)
(?<untag> </ (?&name) > )
# starts like a tag, but has screwed up quotes inside it
(?<nasty>
(?&start_tag)
(?&name)
.*?
(?&end_tag)
)
(?<nontag> [^<] + )
(?<string> (?"ed_value) )
(?<word> (?&name) )
(?<doctype>
<!DOCTYPE
# please don't feed me nonHTML
### (?&WS) HTML
[^>]* >
)
(?<cdata> <!\[CDATA\[ .*? \]\] > )
(?<script> (?= <script ) (?&tag) .*? </script> )
(?<style> (?= <style ) (?&tag) .*? </style> )
(?<comment> <!-- .*? --> )
(?<xml>
< \? xml
(?:
(?&WS)
(?&any_nv_pair)
) *
(?&WS)
\? >
)
(?<xhook> < \? .*? \? > )
)
}six;
our $Meta_Tag_Rx = qr{ $RX_SUBS
(?<META>
(?&start_tag) meta \b
(?:
(?&WS) (?&any_nv_pair)
) +
(?&end_tag)
)
}six;
}
# nobody *ever* remembers to do this!
END { close STDOUT }
- Вы можете написать роман, как сделал Христос
- Вы можете использовать библиотеку DOM, загрузить HTML и использовать xpath и просто использовать
//input[@type="hidden"]
, Или, если вы не хотите использовать xpath, просто получите все входные данные и отфильтруйте, какие из них скрытыgetAttribute
,
Я предпочитаю № 2.
<?php
$d = new DOMDocument();
$d->loadHTML(
'
<p>fsdjl</p>
<form><div>fdsjl</div></form>
<input type="hidden" name="blah" value="hide yo kids">
<input type="text" name="blah" value="hide yo kids">
<input type="hidden" name="blah" value="hide yo wife">
');
$x = new DOMXpath($d);
$inputs = $x->evaluate('//input[@type="hidden"]');
foreach ( $inputs as $input ) {
echo $input->getAttribute('value'), '<br>';
}
Результат:
hide yo kids<br>hide yo wife<br>
В духе лексерного решения Тома Кристиансена, вот ссылка на, казалось бы, забытую в 1998 году статью Роберта Кэмерона " REX: неглубокий анализ XML с регулярными выражениями".
http://www.cs.sfu.ca/~cameron/REX.html
Аннотация
Синтаксис XML достаточно прост, чтобы можно было разобрать документ XML в список его разметки и текстовых элементов, используя одно регулярное выражение. Такой неглубокий анализ XML-документа может быть очень полезен для создания различных легких инструментов обработки XML. Однако сложные регулярные выражения могут быть сложными для создания и даже более сложными для чтения. Используя форму грамотного программирования для регулярных выражений, эта статья документирует набор выражений поверхностного синтаксического анализа XML, которые могут использоваться в качестве основы для простого, правильного, эффективного, надежного и независимого от языка поверхностного анализа XML. Также приведены полные реализации синтаксического анализатора длиной менее 50 строк в Perl, JavaScript и Lex/Flex.
Если вам нравится читать о регулярных выражениях, статья Кэмерона увлекательна. Его письмо лаконично, тщательно и очень подробно. Он не просто показывает вам, как построить регулярное выражение REX, но также предлагает подход для построения любого сложного регулярного выражения из меньших частей.
Я использую регулярное выражение REX в течение 10 лет, чтобы решить проблему, о которой спрашивал первоначальный автор (как мне сопоставить этот конкретный тег, но не какой-то другой очень похожий тег?). Я обнаружил, что разработанное им регулярное выражение полностью надежно.
REX особенно полезен, когда вы сосредотачиваетесь на лексических деталях документа - например, при преобразовании одного типа текстового документа (например, простого текста, XML, SGML, HTML) в другой, где документ может быть недействительным, хорошо сформированный, или даже анализируемый для большей части преобразования. Это позволяет вам ориентироваться на острова разметки в любом месте документа, не мешая остальной части документа.
Хотя мне нравится содержание остальных ответов, они не ответили на вопрос прямо или неправильно. Даже Платиновый ответ был слишком сложным и менее эффективным. Поэтому я был вынужден поставить это.
Я огромный сторонник Regex, когда используется правильно. Но из-за стигмы (и производительности) я всегда заявляю, что правильно сформированный XML или HTML должен использовать парсер XML. И даже лучшая производительность была бы при разборе строк, хотя между читабельностью есть грань, если она выходит из-под контроля. Однако это не вопрос. Вопрос в том, как сопоставить тег ввода скрытого типа. Ответ:
<input[^>]*type="hidden"[^>]*>
В зависимости от вашего вкуса, единственный параметр регулярного выражения, который вам нужно будет включить, - это параметр ignorecase.
Вы можете попробовать это:
<[A-Za-z ="/_0-9+]*>
и для более близкого результата вы можете попробовать это:
<[ ]*input[ ]+type="hidden"[ ]*name=[A-Za-z ="_0-9+]*[ ]*[/]*>
Вы можете проверить свой шаблон регулярных выражений здесь http://regex pal.com/
эти патенты хороши для этого:
<input type="hidden" name="SaveRequired" value="False" /><input type="hidden" name="__VIEWSTATE1" value="1H4sIAAtzrkX7QfL5VEGj6nGi+nP" /><input type="hidden" name="__VIEWSTATE2" value="0351118MK" /><input type="hidden" name="__VIEWSTATE3" value="ZVVV91yjY" />
и для случайного порядка type
, name
а также value
Вы можете использовать это:
<[ ]*input[ ]*[A-Za-z ="_0-9+/]*>
или же
<[ ]*input[ ]*[A-Za-z ="_0-9+/]*[ ]*[/]>
на этом:
<input name="SaveRequired" type="hidden" value="False" /><input type="hidden" name="__VIEWSTATE1" value="1H4sIAAtzrkX7QfL5VEGj6nGi+nP" /><input type="hidden" name="__VIEWSTATE2" value="0351118MK" /><input name="__VIEWSTATE3" type="hidden" value="ZVVV91yjY" />
`
кстати, я думаю, что вы хотите что-то вроде этого:
<[ ]*input(([ ]*type="hidden"[ ]*name=[A-Za-z0-9_+"]*[ ]*value=[A-Za-z0-9_+"]*[ ]*)+)[ ]*/>|<[ ]*input(([ ]*type="hidden"[ ]*value=[A-Za-z0-9_+"]*[ ]*name=[A-Za-z0-9_+"]*[ ]*)+)[ ]*/>|<[ ]*input(([ ]*name=[A-Za-z0-9_+"]*[ ]*type="hidden"[ ]*value=[A-Za-z0-9_+"]*[ ]*)+)[ ]*/>|<[ ]*input(([ ]*value=[A-Za-z0-9_+"]*[ ]*type="hidden"[ ]*name=[A-Za-z0-9_+"]*[ ]*)+)[ ]*/>|<[ ]*input(([ ]*name=[A-Za-z0-9_+"]*[ ]*value=[A-Za-z0-9_+"]*[ ]*type="hidden"[ ]*)+)[ ]*/>|<[ ]*input(([ ]*value=[A-Za-z0-9_+"]*[ ]*name=[A-Za-z0-9_+"]*[ ]*type="hidden"[ ]*)+)[ ]*/>
это не хорошо, но это работает в любом случае.
проверить это в: http://regex pal.com/
Я хотел бы использовать **DOMDocument**
извлечь HTML-код.
$dom = new DOMDocument();
$dom ->loadHTML($input);
$x = new DOMXpath($dom );
$results = $x->evaluate('//input[@type="hidden"]');
foreach ( $results as $item) {
print_r( $item->getAttribute('value') );
}
Кстати, вы можете проверить это здесь - regex101.com. Он показывает результат в режиме реального времени. Некоторые правила для Regexp: http://www.eclipse.org/tptp/home/downloads/installguide/gla_42/ref/rregexp.html Reader.
Предположим, что ваш HTML-контент хранится в строке HTML, а затем, чтобы получить все входные данные, которые содержат скрытый тип, вы можете использовать регулярное выражение
var regex = /(<input.*?type\s?=\s?["']hidden["'].*?>)/g;
html.match(regex);
вышеуказанное регулярное выражение найти <input
с последующим любым количеством символов, пока не получит type="hidden"
или type='hidden', за которым следует любое количество символов до >
/g сообщает регулярному выражению, чтобы найти каждую подстроку, которая соответствует данному шаблону.