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

时间:2010-11-20 05:33:32

标签: html regex parsing

我正在尝试使用此模式匹配<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属性是最后一个,则匹配将失败,因为在我的模式中它是在开始时。

问题:
无论<input>标签中属性的位置如何,我如何更改模式以使其匹配?

P.S。:顺便说一下,我使用 Adob​​e Air RegEx Desktop Tool来测试正则表达式。

8 个答案:

答案 0 :(得分:670)

答案 1 :(得分:122)

  1. 你可以写一本像tchrist一样的小说
  2. 您可以使用DOM库,加载HTML并使用xpath,然后使用//input[@type="hidden"]。或者,如果您不想使用xpath,只需获取所有输入并过滤使用getAttribute隐藏哪些输入。
  3. 我更喜欢#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>
    

答案 2 :(得分:108)

与此处的所有答案相反,对于您正在尝试做的事情,正则表达式是一个非常有效的解决方案。这是因为你没有尝试匹配平衡标签 - 正则表达式是不可能的!但是你只匹配一个标签中的内容,这是完全正常的。

但这是问题所在。你不能只使用一个正则表达式...你需要做一个匹配来捕获<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的力量范围内。

答案 3 :(得分:20)

根据汤姆克里斯蒂安森的词法分析器解决方案的精神,这里有罗伯特卡梅隆看似遗忘的1998年文章的链接, REX:XML浅层解析与正则表达式。

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

  

摘要

     

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

如果您喜欢阅读正则表达式,Cameron的论文非常吸引人。他的写作简洁,透彻,非常详细。他不是简单地向您展示如何构造REX正则表达式,而是一种从较小部分构建任何复杂正则表达式的方法。

我已经使用REX正则表达式打开和关闭了10年来解决最初的海报问题的问题(如何匹配这个特定的标签而不是其他非常相似的标签?)。我发现他开发的正则表达式是完全可靠的。

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

答案 4 :(得分:5)

虽然我喜欢其余答案的内容,但他们并没有直接或正确地回答这个问题。即使是白金的答案也过于复杂,效率也较低。所以我不得不这样做。

如果使用正确的话,我是Regex的忠实拥护者。但由于耻辱(和性能),我总是声明格式良好的XML或HTML应该使用XML Parser。甚至更好的性能也是字符串解析,尽管可读性之间存在一条线,如果它太过于失控。但是,这不是问题。问题是如何匹配隐藏类型的输入标记。答案是:

<input[^>]*type="hidden"[^>]*>

根据您的口味,您需要包含的唯一正则表达式选项是ignorecase选项。

答案 5 :(得分:2)

你可以试试这个:

<[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/

中测试它

答案 6 :(得分:1)

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

答案 7 :(得分:0)

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

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

上面的正则表达式找到<input后跟任意数量的字符,直到它获得type="hidden"或类型=&#39;隐藏&#39;后跟任意数量的字符,直到获得>

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