0

I'm writing a templating engine and I have a syntax that looks like this:

{{If "{{Line}}" != ""}}
    {{If "{{Line}}" != ""}}
        <li id="{{Required:Id}}" class="menuEntry line">
    {{EndIf}}
    <li id="{{Required:Id}}" class="menuEntry line">
{{EndIf}}

Now, I'm searching for a regex to get my if statements, meaning from {{If until {{EndIf}} everything in between should be included.

I came up with the regex:

/({{If)[.]*?[\s\S]*?({{EndIf}})/g

And this does work fine when I have only 1 if statement, but with nested if statements, it goes wrong.

The above regex would give me:

{{If "{{Line}}" != ""}}
    {{If "{{Line}}" != ""}}
    <li id="{{Required:Id}}" class="menuEntry line">
   {{EndIf}}

And in fact I'm expecting to retrieve:

    {{If "{{Line}}" != ""}}
    <li id="{{Required:Id}}" class="menuEntry line">
   {{EndIf}}

Anyone who can provide me some guidance here?

Unihedron
  • 10,902
  • 13
  • 62
  • 72
Complexity
  • 5,682
  • 6
  • 41
  • 84
  • Are you able to not use regex to parse the HTML? If so, I'd go with a parsing library. What language are you implementing this template engine in? – Dave Cooper Aug 07 '14 at 09:03
  • It's not possible for me to do this I'm affraid. I'm using JavaScript for this templating engine. The id is to render complex HTML from this using my engine. – Complexity Aug 07 '14 at 09:04

3 Answers3

1
(\{\{If)((?:(?!\{\{If \"\{\{Line\}\}\" \!= \"\"\}\}|\{\{EndIf\}\}).)*)?(\{\{EndIf\}\})/sg

try this might help you

  • Explain, please. It's too long and complicated to decode. Hint: In regex, you can use the `x` flag to make your regex `extended`. This allows you to place comment blocks within the regex itself, and split it along multiple lines. – Unihedron Aug 07 '14 at 11:22
0

Instead of using .*? that matches everything (including {{If) you can use a negative lookahead matching everything except {{If like this: (?!.*{{If).

Your regex than becomes (you can test it here):

/{{If(?!.*{{If).*?{{EndIf}}/gs

Since Javascript does not have the dotall modifier s to allow dot to match also newlines, you can use a class and its negation instead of the . (as explained here). Then you regex becomes (test it here):

/{{If(?![\s\S]*?{{If)[\s\S]*?{{EndIf}}/g
Community
  • 1
  • 1
enrico.bacis
  • 30,497
  • 10
  • 86
  • 115
0

In JavaScript you can try:

}}\s+({{If [\s\S]*?{{EndIf}})

Get the matched group from index 1

Here is DEMO

Here is the code:

var myString = '...';
var myRegexp = /}}\s*({{If [\s\S]*?{{EndIf}})/gi;
var match = myRegexp.exec(myString);
alert(match[1]);

Read more...

Community
  • 1
  • 1
Braj
  • 46,415
  • 5
  • 60
  • 76