yevg yevg - 1 month ago 15
PHP Question

Using preg_split for templating engine

I am building a templating engine and would like to allow nested logic.

I need to split the following string using "@" for the delimiter but would like to ignore this delimiter - treat is as just another character - if its inside the [square brackets].

Here is the input string:

@if(param1>=7) [ something here @if(param1>9)[ nested statement ] ] @elseif(param2==true) [ 2st condition true ] @else [ default condition ]


The result should look like:

array(

" if(param1>=7) [ something here @if(param1>9)[ nested statement ] ] ",

" elseif(param2==true) [ 2st condition true ] ",

" else [ default condition ] "

)


I believe preg_split is what Im looking for but could use help with the regex

Answer

Regex:

@(?> if | else (?>if)? ) \s*  # Match a control structure
(?> \( [^()]*+ \) \s*)?  # Match statements inside parentheses (if any)
\[  # Match start of block
(?:
    [^][@]*+  # Any character except `[`, `]` and `@`
    (?> \\.[^][@]* )* (@+ (?! (?> if | else (?>if)? ) ) )? # Match escaped or literal `@`s
    |  # Or
    (?R)  # Recurs whole pattern
)*  # As much as possible
\]\K\s*  # Match end of container block

Live demo

PHP:

print_r(preg_split("~@(?>if|else(?>if)?)\s*(?>\([^()]*+\)\s*)?\[(?:[^][@]*+(?>\\.[^][@]*)*(@+(?!(?>if|else(?>if)?)))?|(?R))*\]\K\s*~", $str, -1, PREG_SPLIT_NO_EMPTY));

Output:

Array
(
    [0] => @if(param1>=7) [ something here @if(param1>9)[ nested statement ] ]
    [1] => @elseif(param2==true) [ 2st condition true ]
    [2] => @else [ default condition ]
)

PHP live demo