preg_grep返回空数组的常见原因包括:默认全串匹配而非子串匹配、忽略UTF-8需加u修饰符、非字符串元素被静默转为空字符串、未处理编码混乱、错误依赖i修饰符实现子串搜索,以及性能问题如重复编译或回溯爆炸。

preg_grep 会返回空数组的常见原因
不是正则写错了,而是默认只匹配整个字符串(类似 ^...$ 行为),但很多人误以为它像 strpos 那样“只要包含就命中”。实际它对每个数组元素执行的是全串匹配,不加修饰符时根本不会命中子串。
- 解决办法:在模式开头加
.*,或更规范地用/pattern/i配合PREG_GREP_INVERT外部逻辑处理 - 更推荐加
U(非贪婪)或s(点号匹配换行)修饰符来控制匹配粒度 - 注意:如果数组里有
null或数字,preg_grep会静默跳过——它内部会把非字符串元素转成空字符串再匹配,结果自然失败
匹配中文、emoji 或 UTF-8 字符必须加 u 修饰符
没加 u 时,preg_grep 会把 UTF-8 多字节字符(比如“你好”或 ?)当成乱码切开,导致匹配永远失败,错误提示通常是 PREG_BAD_UTF8_OFFSET_ERROR 或直接返回空数组。
- 正确写法:
preg_grep('/你好/u', $arr),不是/你好/ - emoji 同理:
preg_grep('/?|?/u', $arr) - 如果源数组来自 JSON 解码或数据库,确认
mb_internal_encoding()是UTF-8,否则u修饰符也救不了编码混乱
想忽略大小写又匹配子串?别只靠 i 修饰符
i 只负责字母大小写,对中文、数字、符号无效;而且它不解决“子串匹配”问题。单独写 /abc/i 依然要求整个元素等于 "abc"(忽略大小写),而不是包含 "abc"。
- 真正要“忽略大小写且含子串”,得写成:
preg_grep('/.*abc.*/i', $arr) - 更高效写法是用
stripos+array_filter替代,尤其当数组很大、正则只是简单子串搜索时:array_filter($arr, fn($v) => stripos($v, 'abc') !== false) -
preg_grep的优势在于复杂模式(如邮箱格式、日期片段、带边界限制的词),别为简单查找硬套正则
性能差?可能是用了慢正则或没预编译
每次调用 preg_grep 都会重新编译正则,如果在循环里反复用同一个模式,CPU 时间全耗在编译上了。
立即学习“PHP免费学习笔记(深入)”;
- PHP 7.4+ 支持正则字面量缓存,但仅限于字符串字面量(如
'/foo/'),变量拼接的不行 - 高频场景下,把模式提前赋给变量无用;真要优化,改用
preg_match+foreach手动遍历,并复用$matches引用避免重复分配 - 特别警惕
.*开头的模式——它会触发回溯爆炸,尤其在长文本中。换成[^\n]*或明确长度限制(如.{0,100})更稳
正则不是万能过滤器,preg_grep 的边界很清晰:它只做“字符串级全值匹配”,既不递归进多维数组,也不自动处理类型转换。用之前先问一句——你真的需要正则,还是只是想查个关键词?



















