preg_replace 具有不同大小的数组

preg_replace with arrays of different sizes

我知道答案可能很简单,只是我没有看到。 此代码在布局中为我提供了一个 "tags" 数组(例如 [[tag]]),并且我有一个随请求一起提供的替换数组 ($this->data)。我的第一个倾向是使用 preg_match_all 获取所有标签的数组,然后传入两个数组:

if(isset($this->layout))
{
    ob_start();
    include(VIEWS.'layouts/'.$this->layout.'.phtml');
    $this->layout = ob_get_contents();

    preg_match_all('/\[\[.*\]\]/', $this->layout, $tags);
    print preg_replace($tags, $this->data, $this->layout);
}

但是数组的长度不同(大部分时间)。布局可能会重复使用某些标签,并且传入的数据变量可能不会在布局中包含某些标签。

我觉得必须有一种比 foreach 并在迭代中构建输出更有效的方法来做到这一点。

这个项目太小了,无法实现像 Smarty 或 Twig 这样的完整模板引擎……它实际上只有几页和一些替换。我的客户只想要一种简单的方法来添加页面标题和电子邮件收件人等内容。

如有任何建议,我们将不胜感激。就像我说的,我很肯定这是我忽略的简单事情。

编辑: $this->data 是一组替换文本,如下所示:

tag => replacement_text

编辑 2: 如果我使用 preg_match_all('/\[\[(.*)\]\]/', $this->layout, $tags); 数组只包含标签(没有 [[]]),我只需要一种方法将它们与 $this->data.

中的替换字符串数组相匹配

你可以使用 preg_replace_callback:

$result = preg_replace_callback('/\[\[(?<tag>.*?)]]/', function ($matches) {
  return $this->data[$matches['tag']] ?? $matches[0];
}, $this->layout);

演示:https://3v4l.org/I9Vvh

更短 PHP 7.4 版本:

$result = preg_replace_callback('/\[\[(?<tag>.*?)]]/', fn($matches) => 
  $this->data[$matches['tag']] ?? $matches[0], $this->layout);

使用 ?? $matches[0] 编辑(@Barmar 提供)——这基本上是相同的答案,只是保留它以防 PHP 7.4 语法有用。

您可以简单地使用 str_replace 来完成这项工作,从 $this->data:

创建一个搜索字符串和替换数组
$search = array_map(function ($s) { return "[[$s]]"; }, array_keys($this->data));
$replacements = array_values($this->data);
echo str_replace($search, $replacements, $this->layout);

Demo on 3v4l.org

不需要通过匹配$this->layout得到$tags,信息都在$this->data的key中。您只需要在键周围添加 [[...]]

$tags = array_map(function($key) { 
    return '/\[\[' . preg_quote($key) . '\]\]'; 
}, array_keys($this->data));

另一个解决方案是使用 preg_replace_callback()$this->data;

中查找标签
echo preg_replace_callback('/\[\[(.*?)\]\]/', function($matches) {
    return $this->data[$matches[1]] ?? $matches[0];
}, $this->layout);

请注意,我更改了正则表达式以使用非贪婪量词;您的正则表达式将从第一个标签的开头匹配到最后一个标签的结尾。

如果在 $this->data 中找不到标签,?? $matches[0] 保持不变。