Regex Template Parser ignore new lines

77 Views Asked by At

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

0

There are 0 best solutions below