正则表达式模式在字符串中任何地方都不匹配怎么办?

我尝试使用这个模式来匹配 <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="" />

但是我不确定 typenamevalue属性总是以同样的顺序出现。如果 type属性最后出现,那么匹配将失败,因为在我的模式中它是在开始处。

< p > 问题: < br > 我怎样才能改变我的模式,使其匹配而不管属性在 <input>标签中的位置?译注:

顺便说一下,我使用基于 Adobe Air< em > RegEx 桌面工具 来测试正则表达式。

63478 次浏览

与这里的所有答案相反,因为您正在尝试执行的正则表达式是一个完全有效的解决方案。这是因为您没有尝试匹配平衡标记——这在正则表达式中是不可能的!但是你只匹配了一个标签中的内容,这是完全正常的。

但问题是。您不能只使用一个 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
}

这里的基本原则是,不要试图用一个正则表达式做太多的事情。正如您所注意到的,正则表达式强制执行一定数量的顺序。因此,您需要做的是首先匹配您试图提取的上下文,然后对所需的数据进行子匹配。

然而,我同意一般来说,使用 HTML 解析器可能更容易和更好,你真的应该考虑重新设计你的代码或重新检查你的目标。但是我不得不把这个答案贴出来,作为对解析 HTML 的任何子集都是不可能的下意识反应的反驳: 当你考虑整个规范时,HTML 和 XML 都是不规则的,但是标签的规范是相当规范的,当然是在 PCRE 的权力范围内。

使用正则表达式解析 HTML!

对于您正在尝试的任务,正则表达式是 非常好

确实,大多数人低估了用正则表达式解析 HTML 的难度,因此做得很差。

但这不是计算理论的基本缺陷。

因此,虽然它当然可以做到(这张帖子作为一个存在的证据,这无可争议的事实) ,这并不意味着它 应该是。

您必须自己决定是否能够完成从正则表达式中编写一个专用的、特殊用途的 HTML 解析器的任务。大多数人不是。

am


基于通用正则表达式的 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 任务的演示

下面包含的小 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)
(?= (?&quote)? 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>           (?&quoted_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)
(?:
(?&quoted_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 那样方便、表达能力强大。有一个很大的范围,有些比其他更适合。通常,将正则表达式作为核心语言的一部分而不是作为库表示的语言更容易使用。对于正则表达式,我没有做过任何在 PCRE 中不能做的事情,尽管如果使用 C 语言,程序的结构会有所不同。

最终,其他语言将在正则表达式方面赶上 Perl 现在的水平。之所以这样说,是因为在 Perl 开始运行时,没有人拥有像 Perl 那样的正则表达式。可以说任何你喜欢的东西,但是这正是 Perl 明显胜出的地方: 每个人都复制了 Perl 的正则表达式,尽管它们处于不同的开发阶段。Perl 几乎(不是全部,但是几乎)开创了现代模式中所依赖的所有东西,无论您使用的是什么工具或语言。所以最终其他 威尔赶上来了。

但是它们只能追赶到 Perl 过去的某个时候,就像现在一样。一切都在进步。在正则表达式中(如果没有其他内容的话) ,Perl 引导其他内容。一旦其他人最终赶上 Perl 现在的位置,Perl 将会在哪里?我不知道,但我知道我们也会搬走。也许我们会更接近 Perl6制作模式的风格

如果您喜欢这类东西,但又想在 Perl5中使用它,那么您可能会对 达米安 · 康威的《强大》《精彩》 Regexp: : 语法模块感兴趣。它非常棒,使我在程序中所做的看起来和我的程序一样原始,使得人们在没有空格或字母标识符的情况下将模式填充在一起。看看这个!


简单的 HTML 代码块

下面是我在本文开始时展示的核心部分的解析器的完整源代码。

我是 没有,我建议您应该在一个严格测试的解析类上使用它。但是我厌倦了人们假装没有人可以用正则表达式解析 HTML,因为 他们不能。显然可以,这个程序就是证明。

当然,这并不容易,但 这是可能的!

尝试这样做是非常浪费时间的,因为 应该可以使用好的解析类来完成这个任务。对于试图解析 随心所欲 HTML 的人来说,正确的答案是 没有,这是不可能的。这是一个轻率而虚伪的回答。正确而诚实的回答是,他们不应该尝试这样做,因为从零开始计算太麻烦了; 他们不应该为了重新创造一个运转良好的车轮而折断背部。

另一方面,属于 在一个可预测的子集内的 HTML 非常容易用正则表达式进行解析。难怪人们试图使用它们,因为对于小问题,也许是玩具问题,没有比这更容易的了。这就是为什么区分特定任务和通用任务如此重要,因为这两种任务不一定需要相同的方法。

我希望将来在这里看到一个更公平和诚实的处理关于 HTML 和正则表达式的问题的方法。

这是我的 HTML lexer。它不尝试执行验证解析; 它只标识词法元素。与其说它是 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)
(?&quote) ?
(?<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)
(?= (?&quote)? 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>           (?&quoted_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> (?&quoted_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 }
  1. 你可以像基督那样写小说
  2. 您可以使用 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>

本着 Tom Christiansen 的 lexer 解决方案的精神,这里有一个链接,链接到 Robert Cameron 似乎被遗忘的1998年的文章 使用正则表达式的 XML 浅层解析。

http://www.cs.sfu.ca/~cameron/REX.html

摘要

XML 的语法非常简单,可以使用单个正则表达式将 XML 文档解析为标记和文本项的列表。XML 文档的这种浅层解析对于构造各种轻量级 XML 处理工具非常有用。但是,复杂的正则表达式可能难以构造,甚至更加难以阅读。使用正则表达式的文学编程,本文记录了一组 XML 浅层解析表达式,这些表达式可以作为简单、正确、高效、健壮和与语言无关的 XML 浅层解析的基础。文中还给出了在佩尔、 JavaScript 和 Lex/Flex 中各少于50行的完整浅层解析器实现。

如果你喜欢阅读有关正则表达式的文章,那么 Cameron 的论文非常吸引人。他的文章简洁、全面、非常详细。他不仅向您展示了如何构造 REX 正则表达式,而且还向您展示了如何从较小的部分构建任何复杂的正则表达式。

我断断续续地使用 REX 正则表达式已经有10年了,为的是解决最初发帖人问到的那类问题(我如何匹配这个特定的标签而不是其他非常相似的标签?).我发现他开发的正则表达式非常可靠。

当您关注文档的词法细节时,REX 特别有用——例如,当将一种文本文档(例如,纯文本、 XML、 SGML、 HTML)转换为另一种文档时,在大多数转换中,文档可能无效、格式良好,甚至无法解析。它允许您在文档中的任何位置定位标记岛,而不会干扰文档的其余部分。

你可以试试这个:

<[A-Za-z ="/_0-9+]*>

为了更接近结果,你可以试试这个:

<[ ]*input[ ]+type="hidden"[ ]*name=[A-Za-z ="_0-9+]*[ ]*[/]*>

您可以在这里测试您的正则表达式模式 http://regexpal.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" />

对于 typenamevalue的随机顺序,你可以使用以下命令:

<[ ]*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 选项。

我想使用 **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 读者.

假设你的 html 内容存储在字符串 html 中,那么为了得到每个包含隐藏类型的输入,你可以使用正则表达式

var regex = /(<input.*?type\s?=\s?["']hidden["'].*?>)/g;
html.match(regex);

上面的正则表达式查找 <input后跟任意数量的字符,直到它得到 type="hidden"或 type = ‘ hide’后跟任意数量的字符,直到它得到 >

/g 告诉正则表达式查找与给定模式匹配的每个子字符串。