出于学习的原因,我尝试创建一个PHP模板引擎。
假设我们有以下数组
$regexList = [
'varPattern' => '/{{\s*\$(.*?)\s*}}/',
'loopPattern' => '/@for\((.*?)\)\s*{{((?:[^{}]|(?R))*)}}/',
'statementPattern' => '/@if\((.*?)\)\s*{{((?:[^{}]|(?R))*)}}/'
]以及以下功能
getVar($varName);
loop($arrayName);
getStatementResult($booleanExpression);这根弦叫着:
$string = '
<span>{{ $fullName }}</span>
@for($names as $name)
{{
@if($name == 'Eleandro)
{{
<p>{{ $name }}</p>
}}
}} ';其思想是从上到下读取字符串,并依赖正则表达式列表,找到结果并将其交给正确的函数。
例如:要查找的第一件事必须是{{$string}},因此我们将变量名传递给getVar($matchedVarName)函数。
接下来必须是@loop(){{ }},所以,我们称之为loop($matchedArrayName);
在循环中必须找到@if(){{ }},因此,我们得到结果并给出匹配值的getStatementResult($matchedBooleanExpression)。
我怎样才能按照正确的顺序(从上到下)做这件事?谢谢。
发布于 2017-05-24 14:53:26
如果您将PREG_OFFSET_CAPTURE标志用于preg_match_all,则这是可能的。该标志将做的是,更改捕获的匹配,以将偏移量包含在模式字符串中。现在,我们需要做的唯一一件事就是按照所有匹配的偏移量要求,按照相同的顺序遍历所有的比赛。
这有点棘手,但绝对有可能。我的做法如下:
$matches匹配的preg_match_all。
重要注意事项:匹配是根据每个数组中的偏移量排序的。[0, 0, 0]。为了使它更通用,并让它处理任意数量的正则表达式,我使用了array_fill。1. Determine the next match to handle. This will be the regular expression of which the next match has the minimum offset. I wrote a small `minIndex` function for this.
2. Call the appropriate function (hardcoded in `$functions` below) with the value of the matched group. At this point, we know which function to call because we know which regular expression created this particular match.如果您能够对所有匹配调用相同的函数,我们就可以将所有匹配合并到一个数组中,并按偏移量对它们进行排序。
3.增加匹配正则表达式的索引。
在这一点上,我应该指出,示例中的最后两个正则表达式根本不匹配。这是因为在循环和语句中有{和}的实例。为了演示起见,我只是切断了这些正则表达式的一部分,因此它们只匹配循环/语句的条件。
下面的脚本将打印这个。
getVar('fullName')
loop('$names as $name')
getStatementResult('$name === "Eleandro"')
getVar('name')我相信,这就是你所期望的结果。
// functions
function getVar($varName) {
echo "getVar('$varName')\n";
}
function loop($arrayName) {
echo "loop('$arrayName')\n";
}
function getStatementResult($booleanExpression) {
echo "getStatementResult('$booleanExpression')\n";
}
// input
$string = '
<span>{{ $fullName }}</span>
@for($names as $name)
{{
@if($name === "Eleandro")
{{
<p>{{ $name }}</p>
}}
}} ';
// helper functions
function minIndex($arr) {
$i = 0; $l = count($arr);
$min = false; $minI = -1;
for ($i = 0; $i < $l; ++$i) {
if ($arr[$i] === false) continue; // skip non numbers
if ($min === false || $arr[$i] < $min) {
$min = $arr[$i];
$minI = $i;
}
}
return $minI;
}
// regular expressions
$regexList = [
'varPattern' => '/{{\s*\$(.*?)\s*}}/',
'loopPattern' => '/@for\((.*?)\)\s*{{/',
'statementPattern' => '/@if\((.*?)\)\s*{{/'
];
// functions to map above regexes to
$functions = ['getVar', 'loop', 'getStatementResult'];
// matches per regex
$matchesAll = [];
// combine the above regexes into a single one, run that
foreach ($regexList as $name => $regex) {
unset($matches);
preg_match_all($regex, $string, $matches, PREG_OFFSET_CAPTURE);
$matchesAll[] = $matches;
}
// walk over the matches in order of offset in string
// current match per regex
$indexes = array_fill(0, count($regexList), 0);
// number of matches per regex
$counts = array_map(function($m) { return count($m[0]); }, $matchesAll);
while ($indexes !== $counts) {
$offsets = array_map(function($m, $i) {
return (count($m[0]) > $i ? $m[0][$i][1] : false);
}, $matchesAll, $indexes);
$next = minIndex($offsets);
call_user_func($functions[$next],
$matchesAll[$next][1][$indexes[$next]][0]);
$indexes[$next]++;
}https://stackoverflow.com/questions/44160551
复制相似问题