提问人:Salman 提问时间:11/20/2010 最后编辑:uzluisfSalman 更新时间:5/18/2023 访问量:68755
当正则表达式模式与字符串中的任何位置不匹配时该怎么办?
What to do when a regular expression pattern doesn't match anywhere in a string?
问:
我正在尝试使用这种模式匹配类型字段:<input>
hidden
/<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>
附言:顺便说一句,我正在使用基于Adobe Air的RegEx桌面工具来测试正则表达式。
答:
与这里的所有答案相反,对于您要做的事情,正则表达式是一个完全有效的解决方案。这是因为您没有尝试匹配平衡标签 - 这对于正则表达式是不可能的!但是你只匹配一个标签中的内容,这是完全正常的。
不过,问题来了。你不能只用一个正则表达式来做到这一点......您需要进行一次匹配来捕获标签,然后对其进行进一步处理。请注意,这仅在所有属性值中都没有字符时才有效,因此它并不完美,但对于理智的输入来说应该足够了。<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
}
这里的基本原则是,不要试图用一个正则表达式做太多事情。正如你所注意到的,正则表达式强制执行一定数量的顺序。因此,您需要做的是首先匹配您尝试提取的内容的 CONTEXT,然后对所需的数据进行子匹配。
编辑:但是,我同意,一般来说,使用 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 文件上运行了这段代码——每一个我都可以快速轻松地拿到手。除此之外,我还在专门为破坏朴素解析器而构建的文件上运行它。
这不是一个幼稚的解析器。
哦,我敢肯定它并不完美,但我还没有设法打破它。我认为即使有事情发生,由于程序的结构清晰,修复也很容易适应。即使是正则表达式的程序也应该有结构。
现在这已经不碍事了,让我来回答OP的问题。
使用正则表达式求解 OP 任务的演示
我在下面包含的小程序产生以下输出,因此您可以看到使用正则表达式解析 HTML 可以很好地执行您想要做的事情:html_input_rx
% 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 <[email protected]>
# 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。但另一个问题是,它比几乎任何人想象的都要困难得多。这很容易得出这样的结论,即我的程序证明了你不应该做什么,因为它真的太难了。html_input_rx
我不会不同意这一点。当然,如果经过一些研究,我在程序中所做的一切对你来说都没有意义,那么你就不应该尝试使用正则表达式来完成这种任务。对于特定的 HTML,正则表达式很棒,但对于通用 HTML,它们无异于疯狂。我一直使用解析类,特别是如果它不是我自己生成的 HTML。
正则表达式最适合小的 HTML 解析问题,悲观的正则表达式适合大的 HTML 解析问题
即使我的程序被看作是说明为什么你不应该使用正则表达式来解析一般的HTML——这没关系,因为我有点想让它成为这样☺——它仍然应该让人大开眼界,让更多的人打破编写不可读、非结构化和不可维护的模式的非常普遍和令人讨厌的习惯。
图案不一定是丑陋的,也不一定是坚硬的。如果你创造了丑陋的图案,那是对你的反思,而不是它们。
非常精致的正则表达式语言
我被要求指出,我对你的问题提出的解决方案是用Perl编写的。你感到惊讶吗?你没注意到吗?这个启示是重磅炸弹吗?
诚然,并非所有其他工具和编程语言都像 Perl 那样方便、富有表现力和功能强大。那里有一个很大的范围,有些比其他的更合适。一般来说,将正则表达式作为核心语言的一部分而不是库的语言更容易使用。我没有对正则表达式做任何事情,比如说,PCRE,尽管如果你使用C,你会以不同的方式构建程序。
最终,其他语言将赶上Perl在正则表达式方面所处的位置。我之所以这样说,是因为当 Perl 开始的时候,没有其他人拥有像 Perl 的正则表达式这样的东西。随便说吧,但这就是 Perl 显然获胜的地方:每个人都复制了 Perl 的正则表达式,尽管它们处于不同的发展阶段。Perl 几乎(不是全部,但几乎)开创了你在当今现代模式中所依赖的一切,无论你使用什么工具或语言。所以最终其他人会迎头赶上。
但是他们只会赶上Perl在过去某个时候所处的位置,就像现在一样。一切都在进步。在正则表达式中,如果不出意外的话,Perl 领先的地方,其他人就会跟随。一旦其他人最终赶上了Perl现在的位置,Perl将在哪里?我不知道,但我知道我们也会搬家。也许我们会更接近 Perl₆ 制作模式的风格。
如果你喜欢这种东西,但又想在 Perl₅ 中使用它,你可能会对 Damian Conway 精彩的 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 <[email protected]
# 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 }
评论
- 你可以像tchrist那样写小说
- 您可以使用 DOM 库,加载 HTML 并使用 xpath,然后只使用 .或者,如果您不想使用 xpath,只需获取所有输入并用 过滤隐藏的输入。
//input[@type="hidden"]
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>
评论
本着 Tom Christiansen 的词法分析器解决方案的精神,这里是 Robert Cameron 在 1998 年发表的一篇似乎被遗忘的文章 REX: XML Shallow Parsing with Regular Expressions(《REX:使用正则表达式的 XML 浅层解析》)的链接。
http://www.cs.sfu.ca/~cameron/REX.html
抽象
XML 的语法非常简单,可以使用单个正则表达式将 XML 文档解析为其标记和文本项的列表。XML文档的这种浅层解析对于构建各种轻量级XML处理工具非常有用。然而,复杂的正则表达式可能难以构造,甚至更难阅读。本文使用一种正则表达式的识字编程形式,记录了一组 XML 浅层解析表达式,这些表达式可用于简单、正确、高效、健壮和独立于语言的 XML 浅层解析的基础。还给出了 Perl、JavaScript 和 Lex/Flex 中每个少于 50 行的完整浅层解析器实现。
如果你喜欢阅读有关正则表达式的阅读,那么 Cameron 的论文很吸引人。他的文笔简洁、透彻、非常详细。他不仅向您展示了如何构造 REX 正则表达式,还向您展示了一种从较小的部分构建任何复杂正则表达式的方法。
10 年来,我一直在断断续续地使用 REX 正则表达式来解决最初发帖人提出的问题(我如何匹配这个特定的标签,而不是其他一些非常相似的标签?我发现他开发的正则表达式是完全可靠的。
当您专注于文档的词汇细节时,REX 特别有用 - 例如,将一种文本文档(例如,纯文本、XML、SGML、HTML)转换为另一种文本文档时,文档可能无效、格式不正确,甚至无法解析大多数转换。它允许您将标记岛定位到文档中的任何位置,而不会干扰文档的其余部分。
你可以试试这个:
<[A-Za-z ="/_0-9+]*>
为了获得更接近的结果,您可以尝试以下方法:
<[ ]*input[ ]+type="hidden"[ ]*name=[A-Za-z ="_0-9+]*[ ]*[/]*>
您可以在此处测试您的正则表达式模式 http://regexpal.com/
这些 pattens 对此有好处:
<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://regexpal.com/
虽然我喜欢这些答案的其余部分的内容,但它们并没有真正直接或正确地回答问题。甚至铂金的回答也过于复杂,而且效率也较低。所以我被迫把这个放进去。
如果使用得当,我是正则表达式的忠实拥护者。但是由于污名化(和性能),我总是说格式良好的 XML 或 HTML 应该使用 XML 解析器。更好的性能是字符串解析,尽管如果可读性太失控,则可读性之间有一条线。然而,这不是问题。问题是如何匹配隐藏类型的输入标签。答案是:
<input[^>]*type="hidden"[^>]*>
根据您的风格,您唯一需要包含的正则表达式选项是 ignorecase 选项。
评论
<input type='hidden' name='Oh, <really>?' value='Try a real HTML parser instead.'>
>
>
Ya, <really>!
/>
是 XML-ism;它在任何版本的 HTML 中都不是必需的,除了 XHTML(它从未真正获得太多牵引力,并且几乎被 HTML5 取代)。你说得对,那里有很多混乱的、不真正有效的 HTML,但一个好的 HTML(不是 XML)解析器应该能够处理其中的大部分;如果他们不这样做,很可能浏览器也不会。
我想用它来提取html代码。**DOMDocument**
$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。它实时显示结果。 关于正则表达式的一些规则: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);
上面的正则表达式找到,后跟任意数量的字符,直到它得到或 type='hidden' 后跟任意数量的字符,直到它得到<input
type="hidden"
>
/g 告诉正则表达式查找与给定模式匹配的每个子字符串。
评论