php正则面试核心是写对模式、选对函数、避坑u修饰符和贪婪匹配:preg_match用于验证或取首个,preg_match_all用于批量提取;中文匹配必加u修饰符;.需用.?或1*防跨标签;手机号验证要考虑边界和号段完整性。" ↩

PHP 正则表达式面试题,核心就考三件事:能不能写对、会不会选函数、有没有踩过 u 修饰符和贪婪匹配的坑。
preg_match 和 preg_match_all 到底该用哪个?
面试常问“提取所有 img 的 src”,但很多人只写 preg_match,结果只拿到第一个 —— 它只找一次,返回 0 或 1;真正要批量提取必须用 preg_match_all。
-
preg_match:适合做「验证」或「取首个匹配」,比如判断手机号是否合法 -
preg_match_all:适合做「提取全部」,比如抓页面中所有src、所有邮箱、所有中文词 - 两者都要求模式字符串用分隔符包裹,比如
/pattern/i,不能漏掉斜杠 - 注意第 3 个参数是引用传入的数组,
preg_match_all($pattern, $str, $matches)后,$matches[1]才是捕获组内容(即括号里的值)
中文匹配为什么加 u 修饰符?不加会怎样?
PHP 默认把字符串当字节流处理。UTF-8 中一个汉字占 3 字节,\x{4e00}-\x{9fa5} 这种 Unicode 范围写法,没 u 就直接失效 —— preg_match 会报错或永远不匹配。
- 错误写法:
preg_match('/[\x{4e00}-\x{9fa5}]/', '你好', $m)→ 返回 false - 正确写法:
preg_match('/[\x{4e00}-\x{9fa5}]/u', '你好', $m)→ 成功匹配 - 不加
u时,\d、\w也只认 ASCII,\w不会匹配汉字,\d不会匹配全角数字 - 如果源码文件不是 UTF-8 编码(比如 GBK),加
u反而会出错,这时得先mb_convert_encoding转码
为什么 .* 经常导致匹配失败或取空?
因为 .* 是贪婪的,默认吃掉尽可能多的字符,直到最后一个符合条件的位置才停。在提取 src="xxx" 时,它可能跨标签吞掉整个 HTML 片段。
- 危险写法:
src="(.*)"→ 遇到src="a.jpg" alt="b" src="c.png"会匹配出a.jpg" alt="b" src="c.png - 安全写法:
src="(.*?)"或src="([^"]*)"→?关闭贪婪,或直接排除引号 - 更健壮的写法:
src="([^">]+)",明确拒绝"和>,避免被畸形 HTML 带偏 - 别迷信
.*?:嵌套结构(如多层div)仍无法靠正则可靠解析,这时候该上 DOMDocument
验证手机号的正则为什么不能只写 ^139\d{8}$?
这个表达式本身没错,但面试官想听的是边界意识 —— 实际业务里,字符串往往带空格、换行、前后有文字,光靠锚点 ^ 和 $ 会漏判或误判。
- 输入可能是:
"手机号:13912345678\n"→^139\d{8}$失败 - 应改用
/139\d{8}/(去掉 ^$)配合trim()预处理,或用/\b139\d{8}\b/匹配单词边界 - 更严一点:中国手机号实际是 1[3-9]\d{9},
139只是其中一种号段,完整验证建议用/^1[3-9]\d{9}$/ - 注意
preg_match返回的是 int(1 或 0),不是布尔值,别直接用在 if 条件里当真值判断(虽然 PHP 会转,但语义不清)
最易被忽略的点:正则不是万能语法分析器。遇到 HTML、JSON、嵌套括号这类结构,硬刚正则迟早翻车 —— 面试时主动提一句“这里更适合用 DOMDocument 或 json_decode”,反而显得靠谱。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











