2011-02-24 18 views
2

我想编写symple(包含一个preg_replace调用)论坛分析器,我遇到嵌套标签的问题。PHP PCRE - 正确的嵌套标签行为

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

当具有:

[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]之间的所有文本。

如果我添加了U改性剂,它太ungreedy - 第一[quote]标签与第一(嵌套和不相关)[/quote]标签配对。

感谢您的帮助!

+0

您可能需要查看递归正则表达式,它可以处理该问题,或者实际使用/创建解析器,而不是仅依赖于正则表达式。 – Orbling 2011-02-24 16:05:04

+2

嗨,giyf:http://stackoverflow.com/questions/2909588/regex-bbcode-perfecting-nested-quote – soju 2011-02-24 16:07:45

回答

1

不要使用正则表达式这一点。使用官方提供的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.

0

递归正则表达式的一些帮助:

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通过递归调用来代替内部引号0。