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);
更短 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);
不需要通过匹配$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]
保持不变。
我知道答案可能很简单,只是我没有看到。
此代码在布局中为我提供了一个 "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);
更短 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);
不需要通过匹配$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]
保持不变。