2015-11-03 78 views
1

我试图用PHP抓取一系列网页,抓取标签和最早标签之间的所有内容。这是我正在使用的正则表达式:HTML的Catastophic回溯问题

|(?<=div id="body">).*?</div>|s 

这对于我正在查看的大多数页面来说似乎都工作得很好。但是,它不会为其他几个人返回任何东西。我将正则表达式插入到regex101.com测试程序中,它告诉我问题在于灾难性的回溯。我试图消除回顾后的语言,甚至玩弄的东西,如:

|id="body">.*?</div>|s 

然而,问题仍然持续。我已经看了一些关于灾难性回溯的其他问题,以及http://www.regular-expressions.info/catastrophic.html文章,但我无法弄清楚如何将这些修复应用到这种特殊情况。

+1

我没有看到,落入灾难性的回溯。你能把我们链接到你试过的regex101例子吗? – Mariano

+0

当然。 https://regex101.com/r/kY8qK0/1 – EAP

+0

为什么你需要一个向后看? 'div id =“body”>。*? '作品也一样。 – sln

回答

0

正则表达式已知会导致带有大型HTML内容的灾难性回溯。在这种情况下,问题无疑是在后退和惰性点匹配的情况下,每当正则表达式引擎向右前进一个符号时,它必须检查符号是否以指定的子字符串开头,并且如果它达到足够的字符产生一场比赛。

这个正则表达式如何工作的一个好主意是看regex101 regex debugger部分。

至于如何分析你的HTML,PHP的DOMDocument和DOMXPath是你最好的朋友:

$html = "<<YOUR_HTML_STRING_HERE>>"; 
$dom = new DOMDocument('1.0', 'UTF-8'); 
$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); 
// Above is the DOM initialization from string example, below is parsing 
$xpath = new DOMXPath($dom); 
$divs = $xpath->query('//div[@id="body"]'); // Get all DIV tags with id=body 

foreach($divs as $div) { 
    echo $dom->saveHTML($div); // Echo the HTML, can be added to array 
} 

IDEONE demo

+1

非常感谢!这正是我需要的。 – EAP

+0

@stribizhev你是积极的,这是*灾难性的回溯*,因为问题是不是真的与指数回溯步骤,因为它会发生在嵌套量词?注意它会引起相同的错误,而不是后视,我相信这是一个普通的* O(n)*超时。 – Mariano

+0

@Mariano:我广泛使用术语灾难性的回溯。超时是由大量的回溯步骤造成的。 –