在PHP中移除嵌套的BBCode(引用)

3

我正在尝试从我的公告板中删除嵌套引用,但是我遇到了一些问题。

示例输入:

[quote author=personX link=topic=12.msg1910#msg1910 date=1282745641]

[quote author=PersonY link=topic=12.msg1795#msg1795 date=1282727068]

The message in the original quote

[/quote]

A second message quoting the first one

[/quote]

[quote author=PersonZ link=topic=1.msg1#msg1 date=1282533805]

A random third quote

[/quote]

示例输出

[quote author=personX link=topic=12.msg1910#msg1910 date=1282745641]

第二个引用中的消息

[/quote]

[quote author=PersonZ link=topic=1.msg1#msg1 date=1282533805]

一个随机的第三方报价

[/quote]

如您所见,嵌套的引用(原始消息)已被删除,以及引用标记。

我似乎无法弄清楚。

当我尝试时

$toRemove = '(\\[)(quote)(.*?)(\\])';
$string = $txt;
$found = 0; echo preg_replace("/($toRemove)/e", '$found++ ? \'\' : \'$1\'', $string);

它会移除每个引用标签的所有出现,除了第一个出现的标签。

但是当我扩展代码时:

$toRemove = '(\\[)(quote)(.*?)(\\])(.*?)(\\[\\/quote\\])';
$string = $txt;
$found = 0; echo preg_replace("/($toRemove)/e", '$found++ ? \'\' : \'$1\'', $string); 

它完全停止工作了。

对此有什么想法吗?


编辑:

谢谢你的帮助,Haggi。

然而我仍然遇到麻烦。

围绕着while循环的部分

while ( $input = preg_replace_callback( '~\[quoute.*?\[/quote\]~i', 'replace_callback', $input ) ) {
// replace every occurence
}

移除额外的u和引号后,页面会无限循环。当匹配被更改时,页面不会执行任何操作。

我已经确定原因是匹配问题。

更改为:

$input = preg_replace_callback( '/\[quote(.*?)/i', 'replace_callback', $input );

代码开始工作了,但是当更改为
$input = preg_replace_callback( '/\[quote(.*?)\[\/quote\]/i', 'replace_callback', $input );

它再次停止工作。

另外,undo_replace 函数存在问题,因为它从未找到存储的哈希值,仅会发出有关未找到索引的警告。我想正则表达式匹配 sha1 不正确。

现在我拥有的完整代码:

$cache = array();
$input = $txt;

function replace_callback( $matches ) {
    global $cache;
    $hash = sha1( $matches[0] );
    $cache["hash"] = $matches[0];
    return "REPLACE:$hash";
}



// replace all quotes with placeholders
$input = preg_replace_callback( '/\[quote(.*?)\[quote\]/i', 'replace_callback', $input );

function undo_replace( $matches ) {
    global $cache;
    return $cache[$matches[1]];
}

// restore the outer most quotes
$input = preg_replace_callback( '~REPLACE:[a-f0-9]{40}~i', 'undo_replace', $input );

// remove the references to the inner quotes
$input = preg_replace( '~REPLACE:[a-f0-9]{40}~i', '', $input );

echo $input;

再次感谢大家提供的任何想法 :)


请将 $cache["hash"] = $matches[0]; 替换为 $cache[$hash] = $matches[0]; - haggi
修复了循环中的错误。请尝试我编辑后的新版本。 - haggi
2个回答

2

第一个保持不变,这很容易发现:

'$found++ ? \'\' : \'$1\''

当 $found 未定义时,它的值为 false,因此返回 $1。然后 $found 被增加到 1(undefined + 1 = 1),所以它大于零,并且每次调用它都会进一步增加。由于任何与零不同的值都被视为 true,因此之后你总是得到 ''。

你想要做的是像这样:

$cache = array();

function replace_callback( $matches ) {
    global $cache;
    $hash = sha1sum( $matches[0] );
    $cache[$hash] = $matches[0];
    return "REPLACE:$hash";
}

// replace all quotes with placeholders
$count = 0;
do {
    $input = preg_replace_callback( '~\[quoute.*?\[/quote\]~i', 'replace_callback', $input, -1, $count );
    // replace every occurence
} while ($count > 0);

function undo_replace( $matches ) {
    global $cache;
    return $cache[$matches[1]];
}

// restore the outer most quotes
$input = preg_replace_callback( '~REPLACE:[a-f0-9]{40}~i', 'undo_replace', $input );

// remove the references to the inner quotes
$input = preg_replace( '~REPLACE:[a-f0-9]{40}~i', '', $input );

由于我手头没有PHP来测试,所以这段代码未经过测试。如果您遇到无法解决的错误,请在此处发布并告知我,我会进行修复。

祝好,
haggi


还有一些问题需要解决,但感谢您的帮助。我已经编辑了原始帖子并附上了我的发现。 - Kevin

0

我曾经尝试过使用 preg_replace 处理嵌套引号的问题,但是没有一个解决方案能够正常工作。因此,我根据自己的需求尝试了自己的小版本。

$position = strrpos($string, '[/quote:');  // this will get the position of last quote
$text = substr(strip_tags($string),$position+17); // this will get the data after the last quote used. 

希望这能帮助到某个人。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接