Анализатор шаблонов регулярных выражений игнорирует новые строки

#php #regex #preg-replace #preg-replace-callback

Вопрос:

Я пытаюсь создать «простой» анализатор регулярных выражений, чтобы сгенерировать некоторые шаблоны в своем проекте. Я сделал этот фрагмент регулярного выражения для сопоставления и разбора циклов — что кажется правильным, и я нахожу все, что хочу, и мой цикл заменяет значения.

Последнее, с чем я борюсь, — это избавление от лишних n символов, которые, похоже, остались после замены внутреннего цикла. Я пробовал добавлять различные n или s удалять их захват, но что-то всегда выключено/оставлено.

Как я могу обновить регулярное выражение, чтобы не переносить разрывы строк из группы захвата тела?

s*(?<body>. n*) довел меня до последнего n перед заключительной улицей.

Шаблон:

 <ul class="row">
    <{ foreach( $Users as $user ) }>
        <li><{ $user }></li>
    <{ endforeach }>
</ul>
 

Ожидаемый:

 <ul class="row">n
    <li>Fred</li>n
    <li>Chris</li>n
    <li>Tor</li>n
</ul>n
 

Фактический:

 <ul class="row">n
    n
        <li>Fred</li>n
    n
        <li>Chris</li>n
    n
        <li>Tor</li>n
    n
</ul>n
 

Регулярное foreeach выражение для захвата loop

 /<{s*foreach(s*$(?<variable>w )s ass $(?<value>w )s*)s*}>(?<body>. )<{s*endforeachs*}>/si
 

Замена заполнителя

 /<{s*$(?<variable>w )?s*}>/i
 

Когда я выполняю замену, он использует совпадающее имя variable , чтобы найти некоторые значения, а затем заменяет все, что он находит в теле.

Вот упрощенная версия того, что работает:

 $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();
}
 

Игровая площадка, показывающая, как работает регулярное
выражение https://regex101.com/r/SAua6n/1

Комментарии:

1. Невозможно пропустить их, сопоставляя строку, содержащую их. Удалите эти разрывы строк после того, как будет найдено совпадение.