1

I work with @if|@else|@endif statement in my HTML code and I need find most nested statement/condition (a condition that don't contain another condition) via preg_replace_callback() function.

When function resolve the condition on last level, it start again with parent IF statement as long as all conditions/IF statements will be solved.

In every iteration I need find the actual most nested conditions.

This is example of my HTML code:

  @if($i%2 == 0)

     <something html> 

        @if($i==2)

           <something html>

           @if($i == 0)

              <something html>

           @endif

        @endif

     <something html>

  @else 

     <something html>

        @if($i==2)

           <something html>

        @endif

     <something html>

  @endif

I try something like:

$pattern = '/@if\s*\(\s*(.*)\s*\)\s*((?!@if|@endif).*)\s*(?:@else\s*((?!@if|@endif).*))?\s*@endif/s';

Thank you in advance for your help.

3

1 Answer 1

1

Your attempt has two problems:

  1. The first capturing group matches the rest of the input: "(.)". You need to exclude the closing parens of the if-condition: "([^)])".
  2. The negative look-ahead on @if and @endif only works for the very first character. After that, it matches the rest of the input with ".". The correct nesting here is "((?!...).)".

This gives the following regex:

@if\s*\(\s*([^)]*)\s*\)\s*(((?!@if|@endif).)*)\s*(?:@else\s*(((?!@if|@endif).)*))?\s*@endif

But please note that this only works if the if-conditions do not contain expressions with parenthesis. If they can contain arbitrarily nested parenthesis, you are screwed. (You probably know this, but regex can not count an arbitrary level of nesting, you need a stack for that).

I used this to help figure out your problem: https://regex101.com/

Sign up to request clarification or add additional context in comments.

2 Comments

If I little bit modified your pattern for my match_array structure ([1] => condition, [2] => true part, [3] => false part) It works perfectly for me in all iterations. /@if\s*\(\s*([^)]*)\s*\)\s*((?:(?!@if|@endif).)*?)\s*(?:@else\s*((?:(?!@if|@endif).)*))?\s*@endif/s
This matches @if(@if(abc)XYZ@endif. You have to move the (?:(?!@if|@endif).)* into the if body, and actually everywhere you are matching characters.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.