Rezen
Rezen

Reputation: 435

Regular expression for templating captures too much

With PHP I'm trying to get my regular expression to match both template references below. The problem is, it also grabs the </ul> from the first block of text. When I remove the /s flag that it only catches the second reference. What I'm a doing wrong?

/{{\%USERS}}(.*)?{{\%\/USERS}}/s 

Here is my string.

<ul class="users">
{{%USERS}}
<li>{%}</li>
{{%/USERS}}
</ul>

{{%USERS}} hello?!{{%/USERS}}

Why is my expression catching too much or too little?

Upvotes: 0

Views: 115

Answers (3)

stema
stema

Reputation: 93026

Why is my expression catching too much or too little?

  1. Its catching too much because the quantifiers are greedy by default (see Li-aung Yip answer +1 for that)

  2. If you remove the modifier s it matches only the second occurrence, because that modifier makes the . also match newline characters, so without it, it's not possible to match the first part, because there are newlines in between.

See the non greedy answer

{{\%USERS}}(.*?){{\%\/USERS}}

here on Regexr, a good place to test regular expressions.

Btw. I removed the ? after the capturing group, its not needed, since * matches also the empty string, so no need to make it additionally optional.

Upvotes: 1

Li-aung Yip
Li-aung Yip

Reputation: 12486

You probably need to use non-greedy quantifiers.

* and + are "greedy". They'll match as many characters as they can.

*? and +? are "non-greedy". They'll match only as many characters as required to move on to the next part of the regex.

So in the following test string:

<alpha><bravo>
  • <.+> will capture <alpha><bravo> (because . matches >< as well!).
  • <.+?> will capture <alpha>.

Upvotes: 2

s.webbandit
s.webbandit

Reputation: 17000

Here is your regexp:

/{{%USERS}}([^{]+({%[^{]+)?){{%/USERS}}/g

Upvotes: 0

Related Questions