PHP preg_match一切,直到

时间:2012-02-24 19:30:04

标签: php regex preg-match negative-lookahead

我有一个博客文章,有时会包含很多文字/图片,我想从该博客中摘录一段。更具体地说,我希望匹配所有内容,直到第二个图像标记

之后

下面是一些示例文本。

我尝试了像

这样的负面前瞻
/[\w\r\n;:',."&\s*<>=-_]+(?!<img)/i

但我无法找到一种方法让前瞻适用于'+'修饰符。任何人都有任何线索,我真的很感激。

*override*
I've been stuck in a room lately, and though it's hard to stay creative all the time,         sometimes you need that extra kick. Well for some us we have to throw pictures of true creative genius at ourselves to stimulate us.

So sit back and soak in some inspiration I've come across the past year.

&nbsp;

&nbsp;

&nbsp;

<figure>
    <a href="">
    <img class="aligncenter" src="http://funnypagenet.com/wp-content/uploads/2011/07/Talesandminimalism_12_www.funnypagenet.com_.jpg" alt="" width="574" height="838" />
    </a>
    <figcaption></figcaption>
</figure>

&nbsp;

&nbsp;

&nbsp;

&nbsp;
<h4 style="text-align: center;">
    <a href="http://funnypagenet.com/tales-and-minimalism/">source</a>
</h4>
Couldn't find who did this, but couldn't explain the movie any simpler

&nbsp;

&nbsp;

&nbsp;

&nbsp;

&nbsp;

&nbsp;

&nbsp;

&nbsp;

&nbsp;

<figure>
    <img class="aligncenter" src="http://brickhut.files.wordpress.com/2011/05/theempirestrikesback1.jpg" alt="" width="540" height="800" />
    <figcaption></figcaption>
</figure>

&nbsp;

&nbsp;

&nbsp;

3 个答案:

答案 0 :(得分:3)

明显的直线切割不适合您的第二张图片:

...
<figure>
    <img class="aligncenter" src="http://brickhut.files.wordpress.com/2011/05/theempirestrikesback1.jpg" alt="" width="540" height="800" />
    <figcaption></figcaption>
</figure>

图像切割后会留下未闭合的元素:

...
<figure>
    <img class="aligncenter" src="http://brickhut.files.wordpress.com/2011/05/theempirestrikesback1.jpg" alt="" width="540" height="800" />

这可能会破坏浏览器内页面的呈现。如果你在这里使用带有正则表达式的preg_match或一些字符串函数,它就不起作用。

您需要的是像DOMDocument这样的DOM解析器,它能够处理HTML:

给出一些类似于你的HTML代码示例:

$html = <<<HTML
dolor sit amet, consectetuer adipiscing elit. <img src="http://example.com/img-a.jpg"> Aenean commodo 
ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, 
nascetur ridiculus mus.

<figure>
    <img src="http://example.com/img-b.jpg">
    <figcaption>Figure Caption</figcaption>
</figure>

Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut.
HTML;

您现在可以使用DOMDocument类在<body>标记内加载HTML块 - 因为它是您操作的整个html主体。当您使用非标准HTML代码(<figure>&amp; <figcaption>)时,您应该在使用libxml_use_internal_errors加载字符串时禁用有关这些代码的警告:

$doc = new DOMDocument();
libxml_use_internal_errors(1);
$doc->loadHTML(sprintf('<body>%s</body>', $html));

这是DOM解析器的基本设置,您的HTML现在位于解析器中。现在是有趣的部分。您想要创建摘录,直到文档的第二个图像。这意味着,应删除该元素之后的所有内容。听起来就像切割我们知道不起作用的字符串一样简单,但这次DOM解析器为我们完成了所有的工作。

您只需要获取所有节点(<tag>,文本,<!-- comments -->,...)并删除它们。第二个<img>标记之后的所有节点(跟随文档顺序)。这些事情可以用 XPath 表示:

/descendant::img[position()=2]/following::node()

PHP的DOM解析器附带XPath,所以让我们这样做:

$xp = new DOMXPath($doc);
$delete = $xp->query('/descendant::img[position()=2]/following::node()');
foreach ($delete as $node)
{
    $node->parentNode->removeChild($node);
}

唯一剩下的就是获得(示例性输出)剩下的摘录。我们知道它都在<body>标签内:

foreach ($doc->getElementsByTagName('body')->item(0)->childNodes as $child)
{
    echo $doc->saveHTML($child);
}

这将为您提供以下内容:

dolor sit amet, consectetuer adipiscing elit. <img src="http://example.com/img-a.jpg"> Aenean commodo 
ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, 
nascetur ridiculus mus.

<figure><img src="http://example.com/img-b.jpg"></figure>

如此示例所示,<figure>标记现已正确关闭。

类似的情况是在特定文字长度或字数后创建摘录:Wordwrap / Cut Text in HTML string

答案 1 :(得分:1)

嗯,这不是正则表达式,但应该有效:

$post = str_ireplace('<img', '!!!<img', $post);
list($p1, $p2) = explode('!!!', $post);
$keep = $p1 . $p2;

在图像标记(!!!)之前放置一个分割标记,将它们分开并保留前两个块,这应该是第二个图像标记之前的所有内容。不需要正则表达式。

修改:因为这是摘录,您可能希望在结果上运行strip_tags()。如果不这样做,您可能会打开一些永远不会关闭的HTML标记。

答案 2 :(得分:0)

如果你真的想要基于正则表达式的解决方案,那么它就是:

// assuming $str is your full HTML text
if ( preg_match_all('~^(.*?<img\s.*?<img\s[^>]*>)~si', $str, $m) )
    print_r ( $m[1] );