PHP preg_replace_callback在命名组的匹配中创建假条目



我有几个" shortcode " "块在文本中,我想用一些HTML实体替换使用preg_replace_callback.

短代码的语法很简单:

[block:type-of-the-block attribute-name1:value attribute-name2:value ...]

带值的属性可以以任意顺序提供。我用来查找这些短代码块的示例正则表达式模式:

/[
(?:block:(?<block>piechart))
(?:
(?:s+value:(?<value>[0-9]+)) |
(?:s+stroke:(?<stroke>[0-9]+)) |
(?:s+angle:(?<angle>[0-9]+)) |
(?:s+colorset:(?<colorset>reds|yellows|blues))
)*
]/xumi

现在,这里是有趣的:PHP命名组匹配不存在。对于像这样的字符串:

[block:piechart colorset:reds value:20]

…生成的$matches数组是(注意"stroke">中的空字符串)和"angle">):

array(11) {
[0]=>
string(39) "[block:piechart colorset:reds value:20]"
["block"]=>
string(8) "piechart"
[1]=>
string(8) "piechart"
["value"]=>
string(2) "20"
[2]=>
string(2) "20"
["stroke"]=>
string(0) ""
[3]=>
string(0) ""
["angle"]=>
string(0) ""
[4]=>
string(0) ""
["colorset"]=>
string(4) "reds"
[5]=>
string(4) "reds"
}

下面是测试代码(您也可以在这里在线执行:https://onlinephp.io/c/2429a):

$pattern = "
/[
(?:block:(?<block>piechart))
(?:
(?:s+value:(?<value>[0-9]+)) |
(?:s+stroke:(?<stroke>[0-9]+)) |
(?:s+angle:(?<angle>[0-9]+)) |
(?:s+colorset:(?<colorset>reds|yellows|blues))
)*
]/xumi";
$subject = "here is a block to be replaced [block:piechart value:25   angle:720]  [block] and another one [block:piechart colorset:reds value:20]";
preg_replace_callback($pattern, 'callbackFunction', $subject);
function callbackFunction($matches)
{
var_dump($matches);
// process matched values, return some replacement...
$replacement = "...";
return $replacement;
};

PHP在$matches数组中创建空条目,只是在匹配的情况下,但是在没有找到实际匹配时不清理它是正常的吗?我做错了什么?如何防止PHP创建这些不应该存在的错误条目?

任何帮助或解释将不胜感激!谢谢!

这种行为是预期的,尽管没有很好的文档记录。在手册<;Subpatterns"

当整个模式匹配时,主题字符串的那一部分匹配子模式的内容被传递回调用者

:

考虑以下与字符串Sunday匹配的正则表达式:

(?(坐):你|(太阳))天

这里Sun存储在后引用2中,而后引用1为空

以及PREG_UNMATCHED_AS_NULL标志的文档(从7.2.0版开始新增)。从手册:

如果传递此标志,则不匹配的子模式报告为null;否则将作为空字符串报告。

然后给你一种方法来解决这个行为:

preg_replace_callback($pattern, 'callbackFunction', $subject, -1, $count, PREG_UNMATCHED_AS_NULL);

如果你采用这种方法,那么在你的回调中,你可以使用array_filter过滤$matches数组来删除NULL值。

$matches = array_filter($matches, function ($v) { return !is_null($v); }))

3v4l.org的演示

您可能不赞成重构,但这正是我的建议。理想情况下,您可以提供一个完全成熟的类,但是作为一个简单的演示,我将展示几个基本的函数。

目标不是脚本速度或简洁,而是将可维护性和开发团队放在首位。

通过建立一种识别、解析和路由[block]占位符的基本方法,您消除了未来开发人员对regex有深入理解的需求。相反,"block"属性可以最容易地添加、修改或删除。

我的buildPiechart()函数不应该从字面上理解。这是一个匆忙编写的脚本,建议在动态构建返回字符串之前利用用户提供的数据验证和清理。

代码(演示):

function renderBlock(array $m) {
$callable = "build$m[1]";
return function_exists($callable)
? $callable($m[2] ?? '')
: $m[0];
}
function buildPiechart(string $payloadString) {
$values = [
'angle' => 0,
'colorset' => 'red',
'stroke' => 1,
'value' => 1
];
$rules = [
'angle' => '/d+/',
'colorset' => '/reds|yellows|blues/i',
'stroke' => '/d+/',
'value' => '/d+/',
];
$attributes = preg_split(
'/h+/u',
$payloadString,
0,
PREG_SPLIT_NO_EMPTY
);
foreach ($attributes as $pair) {
[$key, $value] = explode(':', $pair, 2);
if (
key_exists($key, $values)
&& preg_match($rules[$key] ?? '/.*/u', $value, $m)
) {
$values[$key] = $m[0];
}
}
return sprintf(
'<pie a="%s" c="%s" s="%s" v="%s">',
...array_values($values)
);
}
$text = 'here is a block to be replaced [block:piechart value:25   angle:0]  [block] and [block:notcoded attr:val] another one [block:piechart colorset:reds value:20]';
echo preg_replace_callback(
'/[block:([a-z]+)h*([^]rn]*)]/u',
'renderBlock',
$text
);

输出:

here is a block to be replaced <pie a="0" c="red" s="1" v="25">  [block] and [block:notcoded attr:val] another one <pie a="0" c="reds" s="1" v="20">

根据我的专业经验,当客户发现你可以提供动态占位符替代时——就像第一次纹身一样——他们几乎肯定想要更多。下一个特性请求可能是扩展占位符以接受更多属性或支持全新的占位符。这个基础将为你节省很多时间和烦恼,因为功能已经被抽象成更简单的部分。

相关内容

  • 没有找到相关文章

最新更新