在 PHP 中创建模板处理程序(负向前瞻问题)

发布于 2024-11-29 11:33:47 字数 726 浏览 0 评论 0原文

我正在用 PHP 开发一个小的模板处理程序,比如 smarty,只是一个简单得多的模板处理程序。我以前用过 smarty,但它对我来说太强大了。我以为我已经准备好了,但出现了一个非常烦人的错误。 我的想法很简单。我使用 preg_split 来分离模板命令和 html 代码、进程和内爆。 {foreach} 命令工作得很好,所以我根本不会提及它,该错误出现在 {if} 子句中。 正则表达式的“{if}部分”是:

{if\s+[a-zA-Z0-9\{'\}\=\s\/$\!\=]{1,}\s*}

问题是,由于变量替换,我必须允许大括号,这会导致正则表达式不会在“{if**}”。我尝试了消极前瞻和否定积极前瞻以排除“{if”以避免出现问题,但我没有运气。

模板示例:

{if '{$a}' = 'a'}
    blabla
    {if 'c' = 'c'}
        blabla
    {/if}
{/if}
valami más
{if 'b' != 'b'}
    blabla
{/if}
{if '{$c}' = '{$c}'}
    blabla
{/if}

预期输出:

{if '{$a}' = 'a'}
{if 'c' = 'c'}
{if 'b' != 'b'}
{if '{$c}' = '{$c}'}

有人可以帮忙吗?

I'm developing a little template handler in PHP like smarty just a much simpler one. I used smarty before but it was too robust for me. I thought that I'm ready with my one but a really annoying bug showed up.
My conception is simple. I use preg_split to separate the template commands and the html code, process and implode. the {foreach} command works just fine so I won't mantion it at all, the bug appears in the {if} clause.
The "{if} part" of the regexp is:

{if\s+[a-zA-Z0-9\{'\}\=\s\/$\!\=]{1,}\s*}

The problem is that I have to allow curly brackets because of the variable substitution and that causes the regexp not to stop at the end of the "{if**}". I tried negative look aheads and negate positive look aheads to exclude "{if" to avoid the problem but I had no luck.

An example for the template:

{if '{$a}' = 'a'}
    blabla
    {if 'c' = 'c'}
        blabla
    {/if}
{/if}
valami más
{if 'b' != 'b'}
    blabla
{/if}
{if '{$c}' = '{$c}'}
    blabla
{/if}

Output expected:

{if '{$a}' = 'a'}
{if 'c' = 'c'}
{if 'b' != 'b'}
{if '{$c}' = '{$c}'}

Could somebody please help?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

不醒的梦 2024-12-06 11:33:47

根据您上面的描述,我创建了以下正则表达式。我希望这就是您正在寻找的。

<?php

$string = <<<'EOD'
{if '{$a}' = 'a'}
blabla
{if 'c' = 'c'}
    blabla
{/if}
{/if}
valami más
{if 'b' != 'b'}
blabla
{/if}
{if '{$c}' = '{$c}'}
blabla
{/if}
EOD;

$pattern = "~{if\s+'(?:\\{\\$(?:[A-Za-z0-9]+\\})|(?:[A-Za-z0-9]))'\s+(?:=|(?:!=))\s+'(?:(?:\\{\\$(?:[A-Za-z0-9]+\\}))|(?:[A-Za-z0-9]))'\\}~";

preg_match_all($pattern, $string, $matches);

echo '<pre>'.print_r($matches,1).'</pre>';

?>

输出

Array
(
    [0] => Array
    (
        [0] => {if '{$a}' = 'a'}
        [1] => {if 'c' = 'c'}
        [2] => {if 'b' != 'b'}
        [3] => {if '{$c}' = '{$c}'}
    )

:)

更新答案

考虑到以下评论,我创建了以下正则表达式。我承认这不是迄今为止最好的解决方案,但它可以允许诸如 {if '{$c}' = '{$c}' && 之类的参数。 '{$b}' = '{$b}'}。您可以简单地复制该模式,以允许在单个 if 语句中使用两个以上的表达式。显然,它会增长到一个荒谬的长度!然而,如果这是用于模板引擎,也许它不需要太多扩展?所需的任何其他运算符也可以简单地添加到正则表达式中的适当位置。

我再次意识到这不是解决问题的最佳方法;很抱歉我自己无法创建递归版本。也许其他人也能做到!

$pattern = "~{if\s+(?:(?:'(?:\\{\\$(?:[A-Za-z0-9]+\\})|(?:[A-Za-z0-9]))'\s+(?:=|(?:!=)|(?:==)|(?:<=)|(?:>=))\s+'(?:(?:\\{\\$(?:[A-Za-z0-9]+\\}))|(?:[A-Za-z0-9]))')(?:(?:\s+(?:&&|\\|\\|)\s+)(?:'(?:\\{\\$(?:[A-Za-z0-9]+\\})|(?:[A-Za-z0-9]))'\s+(?:=|(?:!=)|(?:==)|(?:<=)|(?:>=))\s+'(?:(?:\\{\\$(?:[A-Za-z0-9]+\\}))|(?:[A-Za-z0-9]))'))?)\\}~";

测试:

$string = <<<'EOD'
{if '{$a}' = 'a'}
blabla
{if 'c' = 'c'}
blabla
{/if}
{/if}
valami más
{if 'b' != 'b'}
blabla
{/if}
{if '{$c}' = '{$c}'}
blabla
{/if}
{if '{$c}' = '{$c}' && '{$b}' = '{$b}'}
EOD;

结果:

Array
(
[0] => Array
    (
        [0] => {if '{$a}' = 'a'}
        [1] => {if 'c' = 'c'}
        [2] => {if 'b' != 'b'}
        [3] => {if '{$c}' = '{$c}'}
        [4] => {if '{$c}' = '{$c}' && '{$b}' = '{$b}'}
    )
)

Based on your description above, I've created the following regex. I hope this is what you're looking for.

<?php

$string = <<<'EOD'
{if '{$a}' = 'a'}
blabla
{if 'c' = 'c'}
    blabla
{/if}
{/if}
valami más
{if 'b' != 'b'}
blabla
{/if}
{if '{$c}' = '{$c}'}
blabla
{/if}
EOD;

$pattern = "~{if\s+'(?:\\{\\$(?:[A-Za-z0-9]+\\})|(?:[A-Za-z0-9]))'\s+(?:=|(?:!=))\s+'(?:(?:\\{\\$(?:[A-Za-z0-9]+\\}))|(?:[A-Za-z0-9]))'\\}~";

preg_match_all($pattern, $string, $matches);

echo '<pre>'.print_r($matches,1).'</pre>';

?>

Outputs:

Array
(
    [0] => Array
    (
        [0] => {if '{$a}' = 'a'}
        [1] => {if 'c' = 'c'}
        [2] => {if 'b' != 'b'}
        [3] => {if '{$c}' = '{$c}'}
    )

)

Updated Answer

With the below comments in mind, I have created the following regex. I admit it is by far not the best solution, but it works to allow for arguments such as {if '{$c}' = '{$c}' && '{$b}' = '{$b}'}. You could simply duplicate the pattern to allow for more than two expressions in a single if statement. Obviously, it would then grow to a ridiculous length! If this is for a templating engine, however, perhaps it would not need much extending? Any other operators required can also simply be added into the regex at the appropriate place.

Once again, I am aware this isn't the best way of solving the problem; I'm sorry I can't create a recursive version myself. Perhaps someone else will be able to do so!

$pattern = "~{if\s+(?:(?:'(?:\\{\\$(?:[A-Za-z0-9]+\\})|(?:[A-Za-z0-9]))'\s+(?:=|(?:!=)|(?:==)|(?:<=)|(?:>=))\s+'(?:(?:\\{\\$(?:[A-Za-z0-9]+\\}))|(?:[A-Za-z0-9]))')(?:(?:\s+(?:&&|\\|\\|)\s+)(?:'(?:\\{\\$(?:[A-Za-z0-9]+\\})|(?:[A-Za-z0-9]))'\s+(?:=|(?:!=)|(?:==)|(?:<=)|(?:>=))\s+'(?:(?:\\{\\$(?:[A-Za-z0-9]+\\}))|(?:[A-Za-z0-9]))'))?)\\}~";

Tested on:

$string = <<<'EOD'
{if '{$a}' = 'a'}
blabla
{if 'c' = 'c'}
blabla
{/if}
{/if}
valami más
{if 'b' != 'b'}
blabla
{/if}
{if '{$c}' = '{$c}'}
blabla
{/if}
{if '{$c}' = '{$c}' && '{$b}' = '{$b}'}
EOD;

Result:

Array
(
[0] => Array
    (
        [0] => {if '{$a}' = 'a'}
        [1] => {if 'c' = 'c'}
        [2] => {if 'b' != 'b'}
        [3] => {if '{$c}' = '{$c}'}
        [4] => {if '{$c}' = '{$c}' && '{$b}' = '{$b}'}
    )
)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文