I am trying to build a "simple" RegEx parser, to generate some templates in my project. I have made this bit of regex to match and parse loops - which seems to be correct and finding everything I want, and my loop replaces the values.
The last bit I am struggling with is getting rid of extra \n characters, that seem to be left over from the inner loop replacement. I have tried adding various \n or \s to remove their capture, but something is always off/left.
How can I update the regex to not take over the line breaks from the body capture group?
\s*(?<body>.+\n*) got me me to one final \n before the closing ul.
Template:
<ul class="row">
<{ foreach( $Users as $user ) }>
<li><{ $user }></li>
<{ endforeach }>
</ul>
Expected:
<ul class="row">\n
<li>Fred</li>\n
<li>Chris</li>\n
<li>Tor</li>\n
</ul>\n
Actual:
<ul class="row">\n
\n
<li>Fred</li>\n
\n
<li>Chris</li>\n
\n
<li>Tor</li>\n
\n
</ul>\n
The foreeach regex to capture the loop
/<{\s*foreach\(\s*\$(?<variable>\w+)\s+as\s+\$(?<value>\w+)\s*\)\s*}>(?<body>.+)<{\s*endforeach\s*}>/si
The placeholder replacement
/<{\s*\$(?<variable>\w+)?\s*}>/i
When I do the replace, it uses the matched named variable, to look up some values, then replaces anything it finds in the body.
Here is a simplified version of what runs:
$users = ['Users' => 'Fred', 'Jack', 'Chris'];
preg_replace_callback($regex, function (array $matches) use ($variables): string {
$output = '';
foreach (resolveValue($matches, $users) as $value) {
$scope = array_merge(
$this->variables,
[$matches['value'] => $value]
);
$output .= replaceVars($matches['body'], $scope);
}
return $output;
},
$template
);
function replaceVars() {
$regex = '/<{\s*\$(?<variable>\w+)?\s*}>/i';
return (string) preg_replace_callback($regex,
function (array $matches): string {
return resolveValue($matches);
},
$template
);
}
function resolveValue($matches, $scope) {
$variable = $matches['variable'] ?? null;
if (isset($scope[variable])) {
return $scope[variable];
}
throw Exception();
}
A playground showing the regex working https://regex101.com/r/SAua6n/1