PHP正则的基础结构
PHP 的正则并非独立语法,而是通过 PCRE 函数调用。一个模式由分隔符包裹,常用 /,也可用 # 或 ~,避免与路径中的斜杠冲突。分隔符后可跟修饰符,如 i 忽略大小写、u 按 UTF-8 处理、m 多行模式。
$pattern = ‘/^\d{3}-\d{4}$/’;
模式中的 ^ 与 $ 分别锚定开头和结尾,\d 匹配数字,{3} 表示重复三次。初学者最容易忽略锚点,导致 preg_match 在长字符串中“部分命中”而误判。
四个必会的 PCRE 函数
pregmatch 与 pregmatch_all
preg_match 只返回第一次匹配,成功返回 1。第三个参数用于接收捕获组:
preg_match(‘/(\d{4})-(\d{2})-(\d{2})/’, ‘2024-05-18’, $m);
// $m[1] = ‘2024’,$m[2] = ’05’
pregmatchall 则收集全部匹配,适合从文本中批量提取链接、邮箱等。
pregreplace 与 pregreplace_callback
pregreplace 完成替换,支持 $1 反向引用。当替换逻辑需要动态计算时,用 pregreplace_callback 传入闭包,可读性更好,也便于做转义处理。
贪婪与非贪婪:最容易踩的坑
默认量词 *、+ 是贪婪的,会尽可能多匹配。例如 匹配 HTML 标签时,遇到多个标签会一路吞到最后一个 >。加上 ? 改为非贪婪 ,即可逐个匹配。
另一个常见问题是未加 u 修饰符时,中文按字节处理,\w 与 . 的行为可能与预期不符。处理中文文本时,统一加 u 是稳妥做法。
实战:表单验证与内容提取
验证中国大陆手机号可写为 /^1[3-9]\d{9}$/,配合 preg_match 返回布尔值即可。注意校验前先 trim(),避免前后空格造成误判。
提取文本中的 URL 可用:
pregmatchall(‘/https?:\/\/[^\s”\’]+/u’, $text, $links);
字符类中排除空格与引号,能减少把标点吞进链接的情况。
性能与安全建议
正则不是万能工具。能用 strpos、filtervar 解决的简单判断,优先用内置函数,速度更快且意图清晰。复杂正则要警惕灾难性回溯,避免嵌套量词如 (a+)+。对用户输入做正则校验时,务必先用 pregquote 转义需要插入模式的字面量,防止模式被破坏。
调试阶段可用 preglasterror() 查看失败原因,常见如回溯超限或 UTF-8 非法字节。把模式写短、写清楚,比追求“一行搞定”更值得。