通过regex读取带有嵌套循环的模板

时间:2013-03-03 19:06:10

标签: php regex

我有一个模板结构,类似于Twig。我将目前的成功与正则表达式分开。

{% for array as item %}
    {% item.party %}
    {% item %}
{% else %}
    // If empty...
{% endfor %}

{% if !var %}
   // Full
{% else %}
   // Empty
{% endif %}

// Is var full, replace block whit var
{% block var %}
   Some Code
{% endblock %}

正则表达式     preg_match_all('/(?:{% (for|if|block) )(.*?)(?: %})(.*?)({% else %}(.*?))?(?:{% end\1 %})/is', $content, $data);

现在我希望它也可以嵌套。唯一的问题是循环总是走错了路。外循环占据内端,因为它是第一个。

{% for array as item %} // From here on
   {% item.title %}
   {% for item.sub as sub %}
      {% sub.title %}
   {% endfor %} // To here
{% endfor %}

你知道如何让正则表达式选择正确的结尾吗?在第一级的内容上,我也可以重新应用整个功能。但它必须是使用正确结束的正则表达式。

1 个答案:

答案 0 :(得分:1)

以下似乎符合您的要求。

它使用(?R)来允许块内整个表达式的递归匹配 见Recursive patterns  和PCRE

preg_match_all(
    '/(?:{% (for|if|block) )(.*?)(?: %})(?:(?R)|(.*?)({% else %}(.*?))?)*(?:{% end\1 %})/is',
     $content, $data
);

我对您的表达式所做的唯一更改是在非捕获组中围绕块的内部内容子模式添加,并添加(R)替代它:

start(?:(?R)|inner)end

(?R)尝试匹配整个正则表达式,从而匹配外部块中的任何其他块。

您也可以用括号括起(?R),即((?R)),这样这些内部块将在第三个捕获组中可用。