4

I have following code:

$content = <<<HTML
<p>{wrapper btnlabel=&quot;AAA&quot;}zzzzzzzzzzzzzzzzzzzz{/wrapper}</p>

<p>{wrapper btnlabel=&quot;Text&quot;}</p>

<table>
<tbody>
<tr>
<th scope="row">123</th>
<td>1 123</td>
<td>12 123</td>
<td>3 123</td>
<td>1 123 123</td>
</tr>
<tr>
<th scope="row">123</th>
<td>2700 123.</td>
<td>1800 123.</td>
<td>1000 123.</td>
<td>300 123.</td>
</tr>
</tbody>
</table>

<p>{/wrapper}</p>
HTML;

preg_match_all('#(?>{wrapper btnlabel=(?>"|&quot;)(.+)(?>"|&quot;)})(.*){/wrapper}#', $content, $matches);
var_dump($matches);

pattern doesn't match to second {wrapper.... I think its because it split into multiple lines. But when i try s modifier it match whole content from first {wrapper until last {/wrapper} in one. Replacement of \n to '' didn't help. So i'm confused. Maybe i miss something ? https://ideone.com/ZMpSJ7 - here is the same test code

Tony
  • 5,797
  • 3
  • 26
  • 22
  • 4
    Here you are: `$re = "/(?>{wrapper btnlabel=(?>\"|")(.+?)(?>\"|")})(.*?){\\/wrapper}/s"; `. The problem is with a greedy `(.+)` and `(.*)`. – Wiktor Stribiżew Apr 17 '15 at 11:17
  • That works now! Thank you! So when use `s` modifier with greedy `(.+)` it match as much as it can until the last character that match pattern ? – Tony Apr 17 '15 at 11:23
  • Yes, exactly. Until it finds a match, it will go on matching everything. – Wiktor Stribiżew Apr 17 '15 at 11:24

1 Answers1

1

Just as I mentioned in the comments, you should be very careful with greedy patterns, only use them when you need to obtain the largest substring possible including subblocks. In other cases, when you need individual substrings, use lazy matching.

Here is a fixed regex:

(?>{wrapper btnlabel=(?>"|&quot;)(.+?)(?>"|&quot;)})(.*?){\/wrapper}

Sample code:

$re = "/(?>{wrapper btnlabel=(?>\"|&quot;)(.+?)(?>\"|&quot;)})(.*?){\\/wrapper}/s"; 
$str = "<p>{wrapper btnlabel=&quot;AAA&quot;}zzzzzzzzzzzzzzzzzzzz{/wrapper}</p>\n\n<p>{wrapper btnlabel=&quot;Text&quot;}</p>\n\n<table>\n<tbody>\n<tr>\n<th scope=\"row\">123</th>\n<td>1 123</td>\n<td>12 123</td>\n<td>3 123</td>\n<td>1 123 123</td>\n</tr>\n<tr>\n<th scope=\"row\">123</th>\n<td>2700 123.</td>\n<td>1800 123.</td>\n<td>1000 123.</td>\n<td>300 123.</td>\n</tr>\n</tbody>\n</table>\n\n<p>{/wrapper}</p>"; 
preg_match_all($re, $str, $matches);
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563