【问题标题】:PHP PCRE - correct nested tags behaviourPHP PCRE - 正确的嵌套标签行为
【发布时间】:2011-02-24 16:01:12
【问题描述】:

我想编写一个简单的(由一个 preg_replace 调用组成)论坛解析器,但遇到了嵌套标签的问题。

例如如果有人在引用某人引用某人的话,我就无法实现正确的行为。

当有:

[quote=Tom]

[quote=Jerry]
Lorem
[/quote]

Ipsum

[/quote]

Dolor.

我想要这样的东西:

<blockquote>
    <p><strong>Tom wrote</strong></p>
    <blockquote>
       <p><strong>Jerry wrote:</strong></p>
      <p>Lorem</p>
    </blockquote>

    Ipsum
</blockquote>

Dolor.

我有这个代码:

preg_replace('~\[quote (.+)\](.+)\[/quote\]~is', '<blockquote><p><strong>$1</strong> wrote:</p><p>$2</p></blockquote>', $value);

这个版本很贪心。如果我有两个单独的 [quote] 块,则正则表达式会包装第一个 [quote] 和第二个 [/quote] 之间的所有文本。

如果我添加 U 修饰符,它就太不贪心了 - 第一个 [quote] 标记与第一个(嵌套且不相关的)[/quote] 标记配对。

感谢您的帮助!

【问题讨论】:

  • 您要么需要查看递归正则表达式,它可以处理这个问题,要么实际使用/创建解析器,而不是单独依赖正则表达式。

标签: php regex pcre


【解决方案1】:

PEAR HTML_BBCodeParser 包,PHP 也有一个本地扩展来解析这样的代码,查看这个例子:http://www.php.net/manual/en/function.bbcode-create.php

【讨论】:

    【解决方案2】:

    不要为此使用正则表达式。使用官方提供的 PECL 扩展:

    示例(摘自文档):

    <?php
    $arrayBBCode=array(
        ''=>         array('type' => BBCODE_TYPE_ROOT,  'childs' => '!i'),
        'i'=>        array('type' => BBCODE_TYPE_NOARG, 'open_tag' => '<i>',
                        'close_tag' => '</i>', 'childs' => 'b'),
        'url'=>      array('type' => BBCODE_TYPE_OPTARG,
                        'open_tag' => '<a href="{PARAM}">', 'close_tag' => '</a>',
                        'default_arg' => '{CONTENT}',
                        'childs' => 'b,i'),
        'img'=>      array('type' => BBCODE_TYPE_NOARG,
                        'open_tag' => '<img src="', 'close_tag' => '" />',
                        'childs' => ''),
        'b'=>        array('type'=>BBCODE_TYPE_NOARG, 'open_tag' => '<b>',
                        'close_tag' => '</b>'),
    );
    
    $text = <<<EOF
    [b]Bold Text[/b]
    [i]Italic Text[/i]
    [url]http://www.php.net/[/url]
    [url=http://pecl.php.net/][b]Content Text[/b][/url]
    [img]http://static.php.net/www.php.net/images/php.gif[/img]
    [url=http://www.php.net/]
    [img]http://static.php.net/www.php.net/images/php.gif[/img]
    [/url]
    EOF;
    
    $BBHandler = bbcode_create($arrayBBCode);
    echo bbcode_parse($BBHandler, $text);
    ?>
    

    The full docs.

    【讨论】:

      【解决方案3】:

      借助递归正则表达式:

      function replace_quotes_callback($matches) {
          $cite = empty($matches[1]) ? '' : '<p><strong>' . $matches[1] . '</strong> wrote:</p>';
          return '<blockquote>' . $cite . '<p>' . replace_quotes($matches[2]) . '</p></blockquote>';
      }
      
      function replace_quotes($data) {
          return preg_replace_callback('~\[quote(?:=([^\]]+))?\]((?:(?R)|.)*?)\[/quote\]~s', 'replace_quotes_callback', $data);
      }
      

      该模式只匹配最外层的引号块,并且回调函数replace_quotes_callback通过递归调用replace_quotes替换自身内部的引号。

      【讨论】:

        猜你喜欢
        • 2014-01-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多