trouble with preg_replace_callback screwing up text

拜拜、爱过 提交于 2019-12-12 04:32:31

问题


I am trying to replace bbcode quotes like this:

[quote=username]text[/quote] 

which works fine.

If someone is quoting someone, who is also quoting someone else, the problem arises that it only appears to replace one of them, like this sort of text:

[quote=person1][quote=person2][quote]test quoted text[/quote]

another quote[/quote]
one more quote[/quote]

Here are my functions:

// replace specific-user quotes, called by quotes()
function replace_quotes($matches)
{
    global $db;

    $find_quoted = $db->sqlquery("SELECT `username`, `user_id` FROM `users` WHERE `username` = ?", array($matches[1]));
    if ($db->num_rows() == 1)
    {
        $get_quoted = $find_quoted->fetch();
        if (core::config('pretty_urls') == 1)
        {
            $profile_link = '/profiles/' . $get_quoted['user_id'];
        }
        else
        {
            $profile_link = '/index.php?module=profile&user_id=' . $get_quoted['user_id'];
        }
        return '<blockquote><cite><a href="'.$profile_link.'">'.$matches[1].'</a></cite>'.$matches[2].'</blockquote>';
    }
    else
    {
        return '<blockquote><cite>'.$matches[1].'</cite>'.$matches[2].'</blockquote>';
    }
}

// find all quotes
function quotes($body)
{
    // Quoting an actual person, book or whatever
    $pattern = '/\[quote\=(.+?)\](.+?)\[\/quote\]/is';

    $body = preg_replace_callback($pattern, 'replace_quotes', $body);

    // Quote on its own
    $pattern = '/\[quote\](.+?)\[\/quote\]/is';
    $replace = "<blockquote><cite>Quote</cite>$1</blockquote>";

    while(preg_match($pattern, $body))
    {
        $body = preg_replace($pattern, $replace, $body);
    }

    return $body;
}

$body = the actual text sent to it from somewhere, like a comment on something

What am I missing to have the nested stuff work too? As it should be replacing each individual quote.


回答1:


The idea is to rewrite your function like that (not tested):

function quotes($body)
{
    $pattern = '~\[quote=([^]]+)]([^[]*+(?:\[(?!/?quote\b)[^[]*)*+)\[/quote]~i';
    do {
        $body = preg_replace_callback($pattern, 'replace_quotes', $body, -1, $count);
    } while ($count);

    return $body;
}

Where ([^[]*(?:\[(?!/?quote\b)[^[]*)*) matches only substrings without opening or closing quote tags. This way you are sure to only get the innermost quote tags.

Note that there's an other way in the PHP manual to parse a recursive structure, but I'm not sure it is very efficient. (see the preg_replace_callback page).



来源:https://stackoverflow.com/questions/41192978/trouble-with-preg-replace-callback-screwing-up-text

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!