为什么功能正则表达式会失败使用PHP的preg_match_all()?

时间:2011-08-10 03:10:20

标签: php regex

我在PHP脚本中有以下正则表达式

$total_matches = preg_match_all('{

        <a\shref="
        (?<link>[^"]+)
        "(?:(?!src=).)+src="
        (?<image>[^"]+)
        (?:(?!designer-name">).)+designer-name">
        (?<brand>[^<]+)
        (?:(?!title=).)+title="
        (?<title>((?!">).)+)
        (?:(?!"price">).)+"price">\$
        (?<price>[\d.,]+)

}xsi',$output,$all_matches,PREG_SET_ORDER);

这个正则表达式在解析以下内容时似乎工作正常(通过php或在regexr.com上使用解析器(使用相同的选项设置为不区分大小写,扩展,将换行符视为空格):

<a href="http://www.mytheresa.com/us_en/dordogne-120-sandals.html" title=
  "DORDOGNE 120 PLATEAU SANDALEN" class="product-image">
  <img class="image1st" src= "http://mytheresaimages.s3.amazonaws.com/catalog/product/cache/common/product_114114/small_  image/230x260/9df78eab33525d08d6e5fb8d27136e95/P/0/P00027794-DORDOGNE-120-PLATEAU-SANDALEN-STANDARD.jpg"
   width="230" height="260" 
   alt=   "Christian Louboutin - DORDOGNE 120 SANDALS - mytheresa.com GmbH" 
   title= "Christian Louboutin - DORDOGNE 120 SANDALS - mytheresa.com GmbH" /> 
 <img class="image2nd" src=  "http://mytheresaimages.s3.amazonaws.com/catalog/product/cache/common/product_114114/image/230x260/9df78eab33525d08d6e5fb8d27136e95/P/0/P00027794-DORDOGNE-120-PLATEAU-SANDALEN-DETAIL_2.jpg"
width="230" height="260" alt=
"Christian Louboutin - DORDOGNE 120 SANDALS - mytheresa.com GmbH" title=
"Christian Louboutin - DORDOGNE 120 SANDALS - mytheresa.com GmbH" /> <span class=
"availability"><strong>available sizes</strong><br /></span></a>

<div style="margin-left: 2em" class="available-sizes">
<h2 class="designer-name">Christian Louboutin</h2>

<div class="product-buttons">
  <div class="product-button">
    NEW ARRIVAL
  </div>

  <div class="clearer"></div>
</div>

<h3 class="product-name"><a href=
"http://www.mytheresa.com/us_en/dordogne-120-sandals.html" title=
"DORDOGNE 120 SANDALS">DORDOGNE 120 SANDALS</a></h3>

<div class="price-box">
  <span class="regular-price" id="product-price-114114"><span class=
  "price">$805.00</span></span>
</div>

如果我尝试连续解析几个匹配项,它也能正常工作。但是,当我尝试解析整个页面时,这些匹配来自(我有权解析这个)

http://www.mytheresa.com/us_en/new-arrivals/what-s-new-this-week-1.html?limit=12

正则表达式失败(实际上我得到500错误)。我尝试使用

增加回溯限制
ini_set('pcre.backtrack_limit',100000000);
ini_set('pcre.recursion_limit',100000000);

但这并没有解决问题。我想知道我做错了什么导致正则表达式在PHP看起来有效时失败,并在相关页面上匹配代码。摆弄它似乎暗示负面的前瞻(与页面长度相结合)导致问题,但我不知道我是如何搞砸它们的。我正在运行PHP 5.2.17。

2 个答案:

答案 0 :(得分:3)

你犯了一个经典的错误!不要使用正则表达式来解析HTML!它破坏了正则表达式! (这是在“永远不要卷入亚洲的陆战”之后,“当死亡在线时,永远不要反对西西里人。”)。

您应该使用SimpleXML或DomDocument来解析它:

$dom = new DomDocument();
$dom->loadHTML( 'http://www.mytheresa.com/us_en/new-arrivals/'.
                 'what-s-new-this-week-1.html?limit=12' );

$path = new DomXPath( $dom );
// this query is based on the link you provided, not your regex
$nodes = $path->evaluate( '//ul[class="products-grid first odd"]/li' );
foreach( $nodes as $node )
{
    // children 0 = anchor tag you're looking for initially.
    echo $node->children[0]->getAttribute("href");
    // iterate through the other children that way
}

答案 1 :(得分:1)

那些负面的前瞻是聪明的,但是......稍微太聪明了

我同意,你使用太多,不会产生副作用。

现在无法看到哪一个正在狂奔,但是重复.那样......总是会给你贪婪问题。

例如,这个当然是不必要的:

title="
(?<title>((?!">).)

你可以写出来

title="(?<title>.*?)">

......还有更多喜欢它。我会改变它们。

通常,正则表达式调试意味着一次又一次地重新构造和重新描述并再次使用不同的结构,直到您在功能之间找到正确的平衡 >和 mantainability

另一件事:我会使用<a\s+代替<a\s,只是稍微灵活一点。
保持略微灵活,付出代价。

title=可以将自己显示为title\s*=\s*