Reputation: 435
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
Reputation: 93026
Why is my expression catching too much or too little?
Its catching too much because the quantifiers are greedy by default (see Li-aung Yip answer +1 for that)
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
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
Reputation: 17000
Here is your regexp:
/{{%USERS}}([^{]+({%[^{]+)?){{%/USERS}}/g
Upvotes: 0