preg_match_all是唯一正确选择,它将所有完整匹配和捕获组存入$matches数组:默认preg_pattern_order下$matches[0]为全部完整匹配、$matches[1]为第一捕获组全部结果;preg_set_order下每项为一次完整匹配含所有子组。

preg_match 只能取第一个匹配,别用它抓多个
preg_match 的设计目标就是「找到第一个就停」。它返回 1(匹配成功)或 0(失败),即使正则本身能匹配多次,它也只填 $matches[0] 和子组,其余匹配直接丢弃。想拿全部结果,必须换函数。
用 preg_match_all 才能拿到所有匹配项
preg_match_all 是唯一正确选择,它会把所有完整匹配和捕获组都存进 $matches 数组,结构取决于第三个参数 $flags:
-
PREG_PATTERN_ORDER(默认):$matches[0]是所有完整匹配,$matches[1]是第一个捕获组的全部结果 -
PREG_SET_ORDER:每个元素是一次完整匹配的数组,含所有子组,更贴近直觉
示例:
$text = "a1b2c3";
preg_match_all('/(\w)(\d)/', $text, $matches, PREG_SET_ORDER);
// $matches = [
// ['a1', 'a', '1'],
// ['b2', 'b', '2'],
// ['c3', 'c', '3']
// ]
捕获组没写对,$matches 里就空着
常见错误是正则里漏了括号,或者用了非捕获组 (?:...) 却还指望它进 $matches。只有带括号的捕获组才会生成对应索引。
- 写
/abc/→$matches[0]有值,$matches[1]不存在 - 写
/(abc)/→$matches[0]是完整匹配,$matches[1]是"abc" - 写
/(?:abc)/→$matches[1]依然不存在,因为?:明确告诉 PHP 别捕获
性能注意:大文本 + 全局匹配可能卡住
preg_match_all 会扫描全文,如果正则写得松(比如 .*、没锚定 ^/$)、或文本超大,可能回溯爆炸、耗尽内存或超时。
- 加
u修饰符处理 UTF-8 字符,否则中文可能被截断 - 用
^和$锚定边界,避免意外跨行匹配(除非你真需要) - 测试时先用小样本,再逐步放大;生产环境建议加
set_time_limit(5)防死锁
真正要从一段 HTML 或日志里抽几十个 ID,preg_match_all 是稳的;但要是想解析整页 DOM,该上 DOMDocument 就别硬刚正则。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











