Search code examples
phpregextemplatespreg-split

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


Solution

  • 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