在PHP7中正则表达式超时?
下面我有2个正则表达式,它在PHP5.6中工作,但如果字符+空格>1035,则在PHP7.x中不工作。示例:[扰流板]1035个字符的计数+ws[/spoiler]。我使用了这个站点,用它来测试正则表达式,它似乎工作得很好 从中,我可以看出问题可能与正则表达式超时有关?但这是密码,除非我弄错了在PHP7中正则表达式超时?,php,regex,Php,Regex,下面我有2个正则表达式,它在PHP5.6中工作,但如果字符+空格>1035,则在PHP7.x中不工作。示例:[扰流板]1035个字符的计数+ws[/spoiler]。我使用了这个站点,用它来测试正则表达式,它似乎工作得很好 从中,我可以看出问题可能与正则表达式超时有关?但这是密码,除非我弄错了 // [spoiler]Text[/spoiler] preg_match_all('/\[spoiler\]\s*((\s|.)+?)\s*\[\/spoiler\]/', $s, $matches,
// [spoiler]Text[/spoiler]
preg_match_all('/\[spoiler\]\s*((\s|.)+?)\s*\[\/spoiler\]/', $s, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$id = substr(md5($match[1]), 0, 10) . mt_rand(0, 10000);
$s = str_replace($match[0],
'<a href="javascript:klappe_function(\'' . $id . '\')" style="color: #aaa" title="Open Spoiler"><img src="images/plus.png" id="pic' . $id . '" class="spoiler" alt="spoiler" /></a><div id="k' . $id . '" style="display: none;">' . $match[1] . '</div><br />',
$s);
}
// [spoiler=Heading]Text[/spoiler]
preg_match_all('/\[spoiler=(.+?)\]\s*((\s|.)+?)\s*\[\/spoiler\]/', $s, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$id = substr(md5($match[2]), 0, 10). mt_rand(0, 10000);
$s = str_replace($match[0],
'<a href="javascript:klappe_function(\'' . $id . '\')" style="color: #aaa" title="Open ' . myhtmlentities($match[1], ENT_QUOTES) . '"><img src="images/plus.png" id="pic' . $id . '" class="spoiler" alt="spoiler" /> <b>' . $match[1] . '</b></a><div id="k' . $id . '" style="display: none;">' . $match[2] . '</div><br />',
$s);
}
/[spoiler]文本[/spoiler]
预匹配所有('/\[spoiler\]\s*(\s.+?)\s*\[\/spoiler\]/',$s,$matches,预设置顺序);
foreach($matches作为$match进行匹配){
$id=substr(md5($match[1]),0,10).mt_rand(0,10000);
$s=str_replace($match[0],
'.$match[1].
,
$s);
}
//[spoiler=标题]文本[/spoiler]
预匹配所有('/\[spoiler=(.+?)\]\s*(\s.+?)\s*\[\/spoiler\]/',$s,$matches,预设置顺序);
foreach($matches作为$match进行匹配){
$id=substr(md5($match[2]),0,10).mt_rand(0,10000);
$s=str_replace($match[0],
'.$match[2].
,
$s);
}
正如评论所说,正则表达式效率非常低,这可能是原因所在-您可以使用一个正则表达式来完成所有这些:
\[扰流板(:?\=([^\]]+)?\]((:?[^\[]+\124;\[(?!=\/spoiler\]))+)\[\/spoiler\]
匹配\[spoiler
[spoiler
启动非捕获组(不会在$matches中)(:?
匹配\=
=
启动第一个捕获组(
匹配除[^\]]+
字符以外的任何字符一次或多次]
关闭第一个捕获组)
关闭组并使其成为可选)?
启动第二个匹配组(
启动非捕获组(不会在$matches中)(:?
匹配除[^\[]+
字符以外的任何字符一次或多次[
或|
单个\[(?!=\/spoiler\]
字符,只要后面没有[
/spoiler]
重复分组一次或多次)+
关闭第二个匹配组)
匹配\[\/spoiler\]
[/spoiler]
trim($match[1],“\r\n\t”)后,您可以在php中轻松地执行此操作。
这里有两个关键点:
匹配“标题”文本
[^\]+
与[
字符以外的任何字符匹配一次或多次
这比查找任何可能导致“回溯”的字符要快得多,请参见:
与扰流板内容物匹配
启动非捕获组(不会在$matches中)(:?
匹配除[^\[]+
字符以外的任何字符一次或多次[
或|
单个\[(?!=\/spoiler\]
字符,只要后面没有[
/spoiler]
重复分组一次或多次)+
[
字符,但同样不会导致回溯。它通过查找一系列非[
字符或单个[
字符来实现此目的,只要后面没有紧跟/spoiler]
-这是一种“消极的前瞻”,请参见:
尽管如此,如果你想高效地完成这项工作,正则表达式可能不是最好的工具,标记器或者preg_split可能会更好。毫不奇怪,正则表达式是一团糟。如果你替换
(\s|]+?
(“正则表达式性能杀手”)使用+?
并使用/s
修饰符,它将更加高效,但仍然没有那么高效。正则表达式在去除周围空白的同时搜索扰流板标记内的任何文本。您可能更适合简单地捕获扰流板标记内的所有文本,然后将其作为单独的st去除ep
已经匹配了\s
,您的正则表达式可能运行缓慢并且超时,因为它执行了大量的回溯。@Willbanwell:不完全是
匹配除换行符以外的所有字符。您应该使用preg\u match\u all
,而不是使用foreach
循环和str\u replace
uld使用preg\u replace\u callback
。您需要[^\[]+
中的+
吗?对于非捕获组外部的+
来说,它似乎是多余的。第一个实例是捕获您的“头”文本,这比查找任何字符都好,因为这会导致正则表达式引擎做更多的工作。第二个实例是,您仍然可以在扰流板中保留[
字符,因此它查找除[
字符以外的任何字符,或者特别是[
结束标记文本后面不跟其他字符的字符。