如果我想在回调中两次使用相同的“字符串”,如何使用preg_replace_callback


How to use preg_replace_callback if i want to use same "string" twice on a callback?

我写了一个BBcode函数,可以找到匹配项并进行替换。但是,如果我需要使用相同的preg_match它不会正确返回匹配项。

代码为:

<?php
//CODE EXAMPLE
class BBCode {
protected $bbcode = array();
	public function __construct() {
		// Replace [div class="class name(s)"]...[/div] with <div class="...">...</div>
		$this->bbcode["/'[div class='"([^'"]+)'"'](.*?)'['/div']/is"] = function ($match) {
			return "<div class='"$match[1]'">$match[2]</div>";
		};	
	}
	public function rander($str) {
		foreach ($this->bbcode as $key => $val) {
			$str = preg_replace_callback($key, $val, $str);
		}
		return $str;
	}
}
?>

如果我只使用一个标签,它可以正常工作!诸如此类:

$str= "[div class="class1"]this is a div[/div]";

即使我使用不同的标签,它也很好用。

$str= "[div class="class1"][p]this is a  paragraph inside a div[/p][/div]";

但是当我尝试使用:

$str = "[div class="class1"][div class="class2"]A div inside a div[/div][/div]";

它不起作用,输出为:

<div class="class1">[div class="class2"]div inside a div</div>[/div]

<div class="class1"><div class="class2">div inside a div</div></div>

如何修复它才能正常工作?

谢谢!

指向 github 上整个 bbcode 类代码的链接

您的正则表达式将从第一个[div class="..."]匹配到它找到的第一个[/div]。因此,开始和关闭div 不匹配(正如您在示例中也看到的那样)。为防止出现这种情况,请使用环顾四周以防止在有另一个[div[/div时匹配:

"/'[div class='"([^'"]+)'"']((?!'[div|'['/div).)*'['/div']/is"

请注意,这只会匹配一次(仅内部div -pair),因此您必须重复匹配,直到找不到任何内容。

演示:

$str = "a[div class='"b'"]c[div class='"d'"]e[/div]f[/div]g";
$reg = "/'[div class='"([^'"]+)'"']((?!'[div|'['/div).)*'['/div']/is";
preg_match($reg, $str, $matches);
var_dump($matches);

将输出:

array(3)
{
    [0]=>
    string(22) "[div class="d"]e[/div]"
    [1]=>
    string(1) "d"
    [2]=>
    string(1) "e"
}

编辑:是的,正如您评论的那样,它仅替换了第一场比赛。*在错误的地方。试试这个代码:

$str = 'a[div class="b"]c[div class="d"]e[/div]f[/div]g';
$reg = "/^(.*)('[div class='"([^'"]+)'"'])((?!'[div|'['/div).*)'['/div'](.*)$/is";
$result = $str;
$step = 1;
echo "step 0: $result'n";
do {
    $result = preg_replace($reg, "$1<div class='"$3'">$4</div>$5", $result, -1, $count);
    echo "step $step: $result'n";
    $step++;
} while ($count > 0);

这输出:

step 0: a[div class="b"]c[div class="d"]e[/div]f[/div]g
step 1: a[div class="b"]c<div class="d">e[/div]f</div>g
step 2: a<div class="b">c<div class="d">e</div>f</div>g
step 3: a<div class="b">c<div class="d">e</div>f</div>g

注意:现在,它匹配一次太频繁了,循环不是最佳的。