首先,对不起我的英语不好。
我正在尝试使用正则表达式和preg_match_all创建一个PHP模板引擎。
我的正则表达式看起来像:
/\{:[\s]*?[\n]*?[\s]*?if(.*?):\}[\s]*?(.*?)[\s]*?(\{:[\s]?else[\s]?:\}[\s]*?(.*?)[\s]*?)\{:[\s]*?endif[\s]*?:\}/is
我的PHP看起来像:
preg_match_all('/\{:[\s]*?[\n]*?[\s]*?if(.*?):\}[\s]*?(.*?)[\s]*?(\{:[\s]?else[\s]?:\}[\s]*?(.*?)[\s]*?)\{:[\s]*?endif[\s]*?:\}/is', $template, $regs, PREG_PATTERN_ORDER);
for ($i = 0, $iMax = count($regs[0]); $i < $iMax; $i++) {
$condition = $regs[1][$i];
$trueval = $regs[2][$i];
$falseval = $regs[4][$i] ?? false;
$res = eval('return ('.$condition.');');
if ($res===true) {
$template = str_replace($regs[0][$i],$trueval,$template);
} else {
$template = str_replace($regs[0][$i],$falseval,$template);
}
}
在我的模板字符串中,如果只有一个,则是这样的:
{: if $var > 3 :}
The variable $var is > than 3
{: else :}
The variable $var is < than 3
{: endif :}
它会很好地工作。但是,如果我在其中放置另一个,则将不起作用。
{: if $var > 3 :}
The variable $var is > than 3
{: if $var1 < 2 :}
The variable $var1 < than 2
{: else :}
The variable $var1 > than 2
{: endif :}
{: else :}
The variable $var is < than 3
{: endif :}
在这种情况下,preg match全部将无法正常工作,并且将向我输出此内容:
{: if $var > 3 :}
The variable $var is > than 3
{: if $var1 < 2 :}
The variable $var1 is < than 2
{: else :}
The variable $var1 is > than 2
{: endif :}
它将停止在第一个端点,而不是一个好的端点。我绝对不知道该怎么做。如果有人有想法?非常感谢您的时间和帮助!
我找到了一个解决方案,没有使用任何正则表达式。我不知道这是否是最佳做法,但是可以。
首先,我逐行拆分文本:
$text = explode(PHP_EOL, $text);
接下来,我在此$ text上进行学习:
$if = [];
foreach ($test as $key => $line){
if(StringUtils::contains($line, 'if') && (!StringUtils::contains($line, 'endif'))){
$if[$key] = trim($line);
}
}
正如您所看到的,我正在本文中寻找某些内容,并将它们放入具有键行号的数组中。
接下来,我进行最后的学习,检查条件,然后替换所有:
krsort($if);
$var = 4;
$var1 = 1;
foreach ($if as $ifOffset => $ix){
for($i = $ifOffset, $iMax = count($test); $i<$iMax; $i++){
if(StringUtils::contains($test[$i], 'endif')){
$content = StringUtils::getBetween($text, $test[$ifOffset], $test[$i]);
$cond = trim(str_replace('if', '', StringUtils::getBetween($ix, '{:', ':}')));
$res = eval('return ('.$cond.');');
$ph = $test[$ifOffset].$content.$test[$i];
if($res===true){
$text = str_replace($ph, $content, $text);
}else{
$text = str_replace($ph, '', $text);
}
unset($if[$ifOffset]);
break;
}
}
}
$ var和$ var1是我在条件中使用的变量。现在,这个:
{:if $var > 3 :}
<p>Bienvenue {{user}} !</p>
{:if $var1 < 2 :}
<p>Wow ! Tu as la permission !</p>
{:endif:}
{:endif:}
{:if $var > 3 :}
<p>Bienvenue {{user}} !</p>
{:if $var1 < 2 :}
<p>Wow ! Tu as la permission !</p>
{:endif:}
{:endif:}
将输出:
Bienvenue {{user}} !
Wow ! Tu as la permission !
Bienvenue {{user}} !
Wow ! Tu as la permission !
我们在这里!
对于“ StringUtils :: contains”函数,您可以使用:
public static function contains($text, ...$search){
if(!empty($search)){
foreach($search as $key => $value){
if(strpos($text, $value) !== false){
unset($search, $text, $key, $value);
return true;
break;
}
}
unset($search, $text);
}
return false;
}
如果有人有更好的主意,为什么不这样做,但是效果很好!