PHP preg_replace_callback 在命名组的匹配项中创建错误条目

标签 php regex pattern-matching pcre preg-replace-callback

我在文本中有几个“短代码” block ,我想使用 preg_replace_callback 将它们替换为一些 HTML 实体。

短代码的语法很简单:

[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”下的手册中:

When the whole pattern matches, that portion of the subject string that matched the subpattern is passed back to the caller

和:

Consider the following regex matched against the string Sunday:

(?:(Sat)ur|(Sun))day

Here Sun is stored in backreference 2, while backreference 1 is empty

还有 PREG_UNMATCHED_AS_NULL 标志的文档(从 7.2.0 版开始新增)。来自manual :

If this flag is passed, unmatched subpatterns are reported as null; otherwise they are reported as an empty string.

这为您提供了一种解决此行为的方法:

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); }))

Demo on 3v4l.org

关于PHP preg_replace_callback 在命名组的匹配项中创建错误条目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72876472/

相关文章:

php - 如何使用 php 在列表中回显结果

php - MYSQL 选择查询返回不期望的结果

php - 将(不翻译)波斯语字母转换为英文字母,如 PHP 中的谷歌翻译

regex - perl - 如何使用 RegEx 获取所有相似的匹配子字符串

scala - 字符串模式匹配最佳实践

php - 在反向代理后面运行的 symfony 应用程序的 URL

javascript - 如何使用正则表达式在匹配字段后附加字符串

python - Python 是否在 re 模块中使用 NFA 进行正则表达式评估?

syntax - 匹配借用的枚举——为什么这个语法是等价的?

c# - 在包含数字的字符串中查找未知的重复模式