PHP使用preg_match_all仅匹配完整词遇正则编译失败如何解决
方案1:长度降序匹配+占位替换(推荐,可避免匹配短子词条)
核心逻辑是优先匹配更长的技能词条,匹配后替换对应文本避免短词条重复命中,完全规避正则过大问题,适配你需要只保留完整长词条的需求:
// 先将技能词条按长度从长到短排序 usort($skills, function($a, $b) { return mb_strlen($b) - mb_strlen($a); }); $matchedSkills = []; $processedText = $text; foreach ($skills as $skill) { $pattern = '~(?<![\w-])' . preg_quote($skill, '~') . '(?![\w-])~i'; if (preg_match_all($pattern, $processedText, $matches)) { foreach ($matches[0] as $match) { $matchedSkills[] = $match; } // 替换命中内容为等长占位符,避免后续命中内部短词条 $processedText = preg_replace($pattern, str_repeat('#', mb_strlen($skill)), $processedText); } } // 可选:对结果去重 $matchedSkills = array_unique($matchedSkills);
你的文本长度仅800词左右,即便循环数千条词条,性能也完全符合使用要求。
方案2:分块正则匹配(适合无长短词条包含冲突的场景)
将技能拆分为多个小组,控制单组正则长度不超过PCRE编译限制(默认32KB),分组匹配后合并结果:
$matchedSkills = []; // 可根据词条平均长度调整块大小,确保单块正则长度不超过30KB即可 $skillChunks = array_chunk($skills, 300); foreach ($skillChunks as $chunk) { $pattern = '~(?<![\w-])(?:' . implode('|', array_map(function($i) { return preg_quote($i, '~'); }, $chunk)) . ')(?![\w-])~i'; if (preg_match_all($pattern, $text, $matches)) { $matchedSkills = array_merge($matchedSkills, $matches[0]); } } $matchedSkills = array_unique($matchedSkills);
该方案比单条循环匹配性能更高,调整块大小即可完全规避正则过大报错。
内容的提问来源于stack exchange,提问作者Seb
相关产品推荐
相关产品推荐

