1

Hi I'm having some problems with php recurring regexp. I have strings like {{if(x=y)? {{ true do something || false do something else }} in my html files. It will be some kind of basic template engine. If I use

$matches=array();
$content = "{{if(x=y)? true do something || false do something else }}";
preg_match_all('/\{\{if\((.*?)\)\?(.*?)\|\|(.*?)\}\}/is',$content,$matches);

returns the results as I expected.

Array(
 [0] => Array
    (
        [0] => {{if(x=y)?
            true do something 
               ||
            false do something else 
               }}
    )
 [1] => Array
    (
        [0] => x=y
    )
 [2] => Array
    (
        [0] => true do something 
    )
 [3] => Array
    (
        [0] => false do something else 
    )
)

But if the pattern is nested with another one like;

{{if(x=y)?
  {{if(y=z)?
     true do something 
   || 
     false do something else 
  }}
||
  {{if(x=a)?
    true do something 
  || 
   false do something else 
  }}
}} 

it takes the first "}}" chars as end of pattern and fails

Array
(
    [0] => Array
    (
        [0] => {{if(x=y)?
            {{if(y=z)?
          true do something 
            ||
          false do something else 
            }}
        )
    [1] => Array
    (
        [0] => x=y
    )
    [2] => Array
    (
        [0] => {{if(y=z)?
    true do something   
    )
    [3] => Array
    (
        [0] => 
    false do something else     
    )
)

I would like to make a recurring regexp so in each part of true or false it should check if the matched content has same pattern again. The logical part of If is already done. I just need a regexp will match the parts so I can loop thru the results.With my Regexp knowledge this is all I could do so far.EDIT to be more descriptive I need a regexp can parse something like this.

{{if()?{{if()?{{if()?...||...}}||{{if()?...||...}}}}||{{if()?{{if()?...||...}}||{{if()?...||...}}}}}}

but the regexp I used can only catches from first {{if to first }} it finds which returns

{{if(){{if(){{if()...||...}}

which is correct for the regexp. But how can I rule the regexp as "get whole text, find the block between {{if()? and }} till the end and ignore any others if it is not at the end" or "get the most outer {{if()?||}} block. Thanks

8
  • Your syntax isn't quite obvious. Are the brace pairs supposed to be balanced? (they're not in either case). Commented Dec 17, 2012 at 21:12
  • I edited it the way it is on page. sorry. It is like basic if clause for php, but instead of using php code in html template I'm trying to make it easier for my client. so when they put an if clause like this in their content, the template class I made should parse it and replace it with the values predefined. like {{if(pagetitle)?{{ print pagetitle || {{if(company_name)? print company_name|| print ''}} }} Commented Dec 17, 2012 at 21:15
  • Why not just use a real templating system? May I recommend Smarty. Commented Dec 17, 2012 at 22:24
  • Okay, simply put, it's not possible. In your last example you cannot possibly get all three if blocks. You cannot get them in 3 different matches because matches cannot overlap. You also cannot get them in 3 different captures of the same match, because for every capture group (i.e. every set of parentheses) in your pattern, there will always be exactly one capture. If the group is reused (through recursion) you will only the the inner- or outermost block. All you can do with regex is verify correct syntax. Parsing will have to be done separately (of a recursive preg_replace_callback). Commented Dec 17, 2012 at 22:31
  • 1
    @GuyFawkes: "we don't have enough time and sources to learn and implement into our system." I suggest that you if you have the time and resources to write, debug and maintain your own homegrown templating system, including having to rely on the people of StackOverflow to debug basic functionality of it for you, then you probably also could funnel that time and resources into using an existing, well-written, already-debugged templating system. Commented Dec 18, 2012 at 14:39

2 Answers 2

1

Nested patterns are not possible with any kind of regular expressions. It's a fundamental restriction in regexps. You need a more powerful form of parser, such as a lexer.

Shortly put, you'd have to iterate manually through every char of your input, parse possible keywords and keep a memory of how many blocks are open.

You are probably much better off by adjusting an existing template system to your needs.

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

Comments

1

I solved the problem with using link. Author of the script made it simple enough with a different style. In my sample I was trying to match the code blocks with regexp and replace them with the data, but he actually replaced the code blocks into php codes and recreates the files in a different folder with same structure and each time page requested, first checks the file existence and updated time and runs the script. pretty smart. Maybe not a perfect solution and rational but solves my problem. thanks anyway

Comments

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.