tags:

views:

1812

answers:

2

I have the following snippet where I would like to extract code between the {foreach} and {/foreach} using a regular expression:

{foreach (...)}
Some random HTML content <div class="">aklakdls</div> and some {$/r/template} markup inside.
{/foreach}

I already have:

{foreach [^}]*}

but I am unable to match anything after that. Is there any way to match anything BUT {/foreach} as a whole token? Please note that the content between {foreach}{/foreach} can also contain "{$" tokens.

(BaileyP && Tomalak)'s answers are correct, but I have choosen BaileyP's answer for simplicity sake.

+2  A: 

If your regex flavor did not support non-greedy matching, the following would do it, but since it does I recommend @BaileyP's answer.

\{foreach [^}]*\}((?:.(?!\{/foreach\}))*[^{]?)

Depending on your regex favour, negative zero-width look-ahead and non-capturing groups look a little different.

Here are the components:

\{foreach [^}]*\}  // pretty much self-explanatory
(                  // match group one starts (that's what you are looking for)
 (?:               // non-capturing group starts
  .                // anything...
  (?!\{/foreach\}) // ... that is not followed by "{/foreach}"
 )*                // non-capturing group ends, repeat as often as possible
 [^{]?             // match the last character, unless it is "{"
)                  // match group one ends, done
Tomalak
Wow! You are Regex master! It works, but there is one problem, the last character just before the {/foreach} is not matched. How would you solve that?
Vincent
Duh. Of course. Wait a second.
Tomalak
You need to put the dot *after* the lookahead, not before it.
Alan Moore
+4  A: 

I came up with this

/(?:{foreach .*?})(.*?)(?:{\/foreach})/gis

Tested with RegExr

Peter Bailey
Yeah. I'm feeling a bit stupid now. :-D Sometimes I think a bit too complicated, was typing up the same thing just now. +1
Tomalak
It's not foolproof, of course. Nested foreach loops will break it - but that's a problem you can't solve with regular expressions alone anyway.
Peter Bailey
You can do nested foreach loops with Perl6 Grammars, and Perl 5.10 regexps.
Brad Gilbert