Reputation: 197
I have a template structure, which resembles that of Twig. I divide this currently successful with regex.
{% 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 %}
Regex
preg_match_all('/(?:{% (for|if|block) )(.*?)(?: %})(.*?)({% else %}(.*?))?(?:{% end\1 %})/is', $content, $data);
Now I would like that can also nest. The only problem is that the loop always take the wrong end. The outer loop takes the inner end because it is first.
{% for array as item %} // From here on
{% item.title %}
{% for item.sub as sub %}
{% sub.title %}
{% endfor %} // To here
{% endfor %}
Do you know how I get the regex to choose the right end? On the content of the first level, I can also re-apply the entire function. But it must be the regex to use the correct end.
Upvotes: 0
Views: 649
Reputation: 13641
The following seems to meet your requirements.
It uses (?R)
to allow recursive matching of the whole expression within a block.
See Recursive patterns
and PCRE.
preg_match_all(
'/(?:{% (for|if|block) )(.*?)(?: %})(?:(?R)|(.*?)({% else %}(.*?))?)*(?:{% end\1 %})/is',
$content, $data
);
The only changes I made to your expression were additions to surround the block's inner content sub-pattern in a non-capturing group, and to add the (R)
alternative to it:
start(?:(?R)|inner)end
The (?R)
attempts to match the whole regular expression, thereby matching any other blocks within the outer block.
You could also surround the (?R)
with parentheses, i.e. ((?R))
, so these inner blocks will be available in the third capture group.
Upvotes: 1