开发者

Creating template handler in PHP (negative look ahead problem)

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?


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}'}
    )
)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜