有趣的行为与HTML段落标签

时间:2012-08-18 18:36:43

标签: php html regex string

$regex = '#<p.+</p>#s';

我的目标是返回第一个段落标记和最后一个段落标记之间出现的大字符串。这包括所有内容,甚至包括其他段落。

我的正则表达式适用于除段落标记之外的所有内容。我测试了它用'html'替换'p'并返回成功,替换为'script'并返回成功...为什么这些情况会返回true而不是段落?

我仍在研究这个问题,相对确信没有奇怪的转义序列导致正则表达式停止...我想这是因为我可以在第一个和最后一个'html'标记之间提取所有内容。 'html'标签之间的文本还包含我无法提取的所有'p'标签。如果出现某种转义或错误,我认为在提取'html'标签时也会抛出相同的错误。我试过preg_quote()没有成功。

也许我需要将专用于正则表达式处理的内存设置得更高,以便它可以处理整个文档?

更新:在大多数情况下,前导'p'(在大多数情况下)不是同一段落标记的结尾'/ p'标记。

更新:返回的结果将类似于:

<p>this is the first tag</p>this is a bunch of text from the document, could be all manner of tags <p>this is the last paragraph tag</p>

更新:代码示例     

$htmlArticle = <<< 'ENDOFHTML'

Insert data from pastebin here
http://pastebin.com/4A3FYGc8

ENDOFHTML;

$pattern = '#<html.+/html>#s'; // Works fine, returns all characters between first <html and last /html
$pattern = '#<script.+/script>#s'; // Works fine, same as above
$pattern = '#<p.+/p>#s'; // Returns nothing, nothing at all. :'(

preg_match($pattern, $htmlArticle, $matches);

var_dump($matches);

?>

解决方案:     ini_set('pcre.backtrack_limit','1000000');

我已经用尽了我的回溯限制。这是php.ini文件中的一个设置,可以使用ini_set()在代码中设置。奇怪的是,我使用ini_set()设置值以匹配我的php.ini文件中的值...所以它应该从一开始就有效。 ---一旦我发布解决方案,谢谢你的到来。

2 个答案:

答案 0 :(得分:0)

这很好奇。它没有返回错误,使用较短的文档似乎返回匹配。我不明白为什么会这样。我已经在没有问题的情况下在大量文档上使用了正则表达式。

请注意,这会产生匹配:#<p\b.+<\#s

也许尝试使用backtrack limit,因为有很多</p>个匹配。但是,如果限制太低,我希望preg_match返回False,而不是0!

作为解决方法,请尝试以下方法:

function extractBetweenPs($data) {
$startoffset = null;
$endoffset = null;
if (preg_match('/<p\b/', $data, $matches, PREG_OFFSET_CAPTURE)) {
    $startoffset = $matches[0][1];
    $needle = '</p>';
    $endoffset = strrpos($data, $needle);
    if ($endoffset !== FALSE) {
        $endoffset += strlen($needle);
    } else {
        // this will return everything from '<p' to the end of the doc
        // if there is no '</p>'
        // maybe not what you want?
        $endoffset = strlen($data);
    }
    return substr($data, $startoffset, $endoffset-$startoffset);
}
return '';
}

也就是说,这是一个非常奇怪的要求 - 将结构化文档的任意部分视为blob。也许你可以退一步说出你更广泛的目标是什么,我们可以提出另一种方法吗?

答案 1 :(得分:-1)

正则表达式不是可用于正确解析HTML的工具。

您所需要的只是DOMDocument

$dom = new DOMDocument();
$dom->loadHTML($your_html);
$node = $dom->getElementsByTagName('p')->item(0);
$dom2 = new DOMDocument();
$node = $dom2->importNode($node, true);
$dom2->appendChild($node);
echo $dom2->saveHTML();