我正在制作一个模板系统,我可以输入:
<t:category:item:parameter1:parameter2...>
并将其替换为文件中的文本。可选参数作为%1
,%2
...
到目前为止,我有这个:
$data = preg_replace_callback("/<t:([^:]+):([^>]+)>/",function($m) use (&$userdata) {
static $fcache = Array();
$parse = function($file) use (&$fcache,&$lang) {
// parse the file if it's a new one. False indicates success, otherwise error message is returned
if( !isset($fcache[$file])) {
if( !file_exists("text/".$lang."/".$file.".html")) $lang = "en";
if( !file_exists("text/".$lang."/".$file.".html")) return "<div class=\"alert\">ERROR: File ".$file." not found.</div>";
$k = "";
foreach(file("text/".$lang."/".$file.".html") as $l) {
if( substr($l,0,1) == "|") $k = rtrim(substr($l,1));
else $fcache[$file][$k] .= $l;
}
}
return false;
};
$lang = $userdata && $userdata['language'] ? $userdata['language'] : "uk";
list(,$file,$d) = $m;
$params = explode(":",$d);
$section = array_shift($params);
if( $e = $parse($file)) return $e;
if( !$fcache[$file][$section]) {
$lang = "uk";
if( $e = $parse($file)) return $e;
}
return preg_replace_callback("/%(\d+)/",function($i) use ($params) {
return htmlspecialchars_decode($params[$i[1]-1]);
},trim($fcache[$file][$section]));
},$data);
文本文件的格式为:
|key
replacement text
|otherkey
more text %1
无论如何,要指出:如果其中一个参数本身就是替换字符串怎么办?例如,如果我想要一个像“快来拜访他”的字符串怎么办? - 我希望它有类似的东西:
<t:person:visit:<t:grammar:pronoun_object_m>>
该文件将包含:
|visit
Come and visit %1 soon!
|pronoun_object_m
him
但是,当前函数会将参数作为文字<t:grammar:pronoun_object_m
,并且会在短语末尾显示额外的>
:
快来访问&lt; t:grammar:pronoun_object_m吧!&gt;
实际上会显示为:
快来访问
由于未更新的替换看起来像HTML标记...
我很确定我需要一个递归的正则表达式,但是我对它们如何工作非常困惑。任何人都可以解释我如何“递归”我的正则表达式以允许这样的嵌入参数?
答案 0 :(得分:2)
递归解决方案的问题是,它们与preg_replace
的效果不佳。它们主要用于preg_match
。原因是您只能访问在递归中重用的模式的最后(最内部)捕获。所以即使preg_replace_callback
在这里也无济于事。
这是另一种可能性:
在<t:person:visit:<t:grammar:pronoun_object_m>>
中,您获得输出的原因是,您的正则表达式将与此匹配:
<t:person:visit:<t:grammar:pronoun_object_m>
(它不能更进一步,因为你在占位符中不允许>
。)
有几种方法可以解决这个问题。对于初学者,您也可以在占位符中禁止<
(而不仅仅是>
):
"/<t:([^:]+):([^<>]+)>/"
现在,您的模式始终只能找到最里面的占位符。因此,您可以反复调用preg_replace_callback
,直到不再进行替换。如何找到这个?添加可选的第四个和第五个参数:
do
{
preg_replace_callback("/<t:([^:]+):([^<>]+)>/", $function, $data, -1, $count);
} while($count);
我还建议(为了易读性)在preg_replace_callback
函数之外定义回调。