如果我想在回调中使用相同的 "string" 两次,如何使用 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>
我怎样才能让它正常工作?
谢谢!
您的正则表达式将匹配它找到的第一个 [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, "<div class=\"\"></div>", $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
注意:现在,它匹配一次太频繁了,循环不是最优的。
我编写了一个 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>
我怎样才能让它正常工作?
谢谢!
您的正则表达式将匹配它找到的第一个 [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, "<div class=\"\"></div>", $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
注意:现在,它匹配一次太频繁了,循环不是最优的。