为什么 preg_match_all 打破这个正则表达式?
Why does preg_match_all break with this regex?
我今天大部分时间都在与一个神秘的崩溃作斗争,我终于解决了这个问题,但并不真正理解我自己的修复方法。
代码的目的是替换模板中的占位符。
下面是我需要重现问题的最终最小 PHP 代码。
$path = realpath("path_to_template.html");
$content = file_get_contents($path);
$loop_regex = '/{{\*(\w+)}}((?:.|\n)+?){{\/\w+}}/s';
$data = array(
"Trainees"=> array(
array(
"display_name" => "Joe",
"status" => "Pending",
"invited_date" => "01 Sep 2018",
"percentage" => "80%"
)
)
);
preg_match_all($loop_regex, $content, $output_array);
模板:
<table>
<tbody>
<tr>
<th>Trainee</th>
<th>Status</th>
<th>Invited</th>
<th>Score</th>
<th>Action</th>
</tr>
{{*Trainees}}
<tr>
<td>{{display_name}}</td>
<td>{{status}}</td>
<td>{{invited_date}}</td>
<td>{{percentage}}</td>
<td>Some action button</td>
</tr>
{{/Trainees}}
</tbody>
</table>
在我尝试向模板中添加更多内容之前,一切都很好。突然间,ERR_CONNECTION_RESET 每当它碰到 preg_match_all.
断点好像只和{{练习生}}组内的内容大小有关,当达到395个字符左右的时候就断了。
我通过 Drupal 博客发现将此添加到 Apache httpd.config 可以修复它。
<IfModule mpm_winnt_module>
ThreadStackSize 8388608
</IfModule>
但我真的不明白为什么这段代码会超过堆栈大小,因此我仍然可以轻松地用更多内容打破它。
欢迎任何理论。
环境:
WAMPServer 3.0.8,PHP 5.6.25,Apache 2.4.23
表达式
{{\*(\w+)}}((?:.|\n)+?){{\/\w+}}
效果很差,更好用
{{\*(\w+)}}(.+?){{/\w+}}
与其他分隔符,例如~
代替。
您的旧表达式需要 780 步(参见this demo on regex101.com) while the latter only needs 404 steps (see another demo here)。
顺便说一句,我还发现切换到 PHP 7.0.10 也可以避免这个问题,但这可能会掩盖我原来的正则表达式的低效,所以 Jan 的回答似乎是正确的。
我今天大部分时间都在与一个神秘的崩溃作斗争,我终于解决了这个问题,但并不真正理解我自己的修复方法。
代码的目的是替换模板中的占位符。
下面是我需要重现问题的最终最小 PHP 代码。
$path = realpath("path_to_template.html");
$content = file_get_contents($path);
$loop_regex = '/{{\*(\w+)}}((?:.|\n)+?){{\/\w+}}/s';
$data = array(
"Trainees"=> array(
array(
"display_name" => "Joe",
"status" => "Pending",
"invited_date" => "01 Sep 2018",
"percentage" => "80%"
)
)
);
preg_match_all($loop_regex, $content, $output_array);
模板:
<table>
<tbody>
<tr>
<th>Trainee</th>
<th>Status</th>
<th>Invited</th>
<th>Score</th>
<th>Action</th>
</tr>
{{*Trainees}}
<tr>
<td>{{display_name}}</td>
<td>{{status}}</td>
<td>{{invited_date}}</td>
<td>{{percentage}}</td>
<td>Some action button</td>
</tr>
{{/Trainees}}
</tbody>
</table>
在我尝试向模板中添加更多内容之前,一切都很好。突然间,ERR_CONNECTION_RESET 每当它碰到 preg_match_all.
断点好像只和{{练习生}}组内的内容大小有关,当达到395个字符左右的时候就断了。
我通过 Drupal 博客发现将此添加到 Apache httpd.config 可以修复它。
<IfModule mpm_winnt_module>
ThreadStackSize 8388608
</IfModule>
但我真的不明白为什么这段代码会超过堆栈大小,因此我仍然可以轻松地用更多内容打破它。
欢迎任何理论。
环境: WAMPServer 3.0.8,PHP 5.6.25,Apache 2.4.23
表达式
{{\*(\w+)}}((?:.|\n)+?){{\/\w+}}
效果很差,更好用
{{\*(\w+)}}(.+?){{/\w+}}
与其他分隔符,例如~
代替。
您的旧表达式需要 780 步(参见this demo on regex101.com) while the latter only needs 404 steps (see another demo here)。
顺便说一句,我还发现切换到 PHP 7.0.10 也可以避免这个问题,但这可能会掩盖我原来的正则表达式的低效,所以 Jan 的回答似乎是正确的。