php正则表达式学习笔记
前言先说一件容易混淆的事PHP 里的「正则表达式」其实分两套历史一套是已经消失的 POSIX 扩展一套是现在唯一在用的 PCRE。POSIX 那套函数ereg()、eregi()、ereg_replace()、eregi_replace()、split()、spliti()、sql_regcase()在 PHP 5.3 就被废弃在 PHP 7.0 中被彻底移除。现在网上还能搜到大量讲ereg()的教程那些代码在 PHP 7 及以上版本里会直接报「Call to undefined function」。PHP 8 时代只认preg_*系列底层的 PCRE 引擎负责解析和执行。第二个常见误解是把正则当成「万能的格式校验器」。正则擅长的是在文本里找符合形状的片段不擅长判断语义是否成立。比如用正则去完整校验一个邮箱地址是否符合 RFC 规范是件既做不到又没必要的事——这件事应该交给filter_var($email, FILTER_VALIDATE_EMAIL)。分不清这两件事就会写出越来越长、越来越难维护的模式。本文是一份聚焦 PHP 侧的 PCRE 笔记定界符与修饰符、常用元字符、捕获组与断言以及两条必须小心的性能红线。一、定界符与修饰符一个 PHP 正则模式是字符串第一个字符是定界符最后一个字符是同一个定界符。定界符可以是任何非字母、非数字、非反斜杠、非空白的字符常用的是斜杠、井号和波浪号?php // 适用于 PHP 8.0$p1 /\d/;$p2 #\d#;$p3 ~\d~;var_dump(preg_match($p1, abc123)); // int(1)var_dump(preg_match($p2, abc123)); // int(1)var_dump(preg_match($p3, abc123)); // int(1)用井号做定界符的好处是处理路径、URL 这类含大量斜杠的文本时不必转义#^/var/log/#比/^\/var\/log\//好读得多。反过来模式里出现的定界符字符必须转义。定界符之后可以跟修饰符它们控制匹配行为修饰符作用i不区分大小写m多行模式行首行尾锚点按每行计算s让点号也匹配换行x扩展模式忽略模式里的空白与注释u按 UTF-8 解释模式与目标串U反转量词的贪婪性默认变懒惰A强制从头开始匹配D行尾锚点只匹配字符串真正的结尾S旧版本中用于预分析模式以加速匹配现代 PCRE 已不再需要关于u不加它时正则引擎把目标串当作字节序列点号匹配一个字节量词数的也是字节。中文字符在 UTF-8 下一个字占 3 个字节所以张三这种两个字的中文在没有u的模式下长度是 6。这一点造成的错误非常隐蔽?php // 适用于 PHP 8.0var_dump(preg_match(/^.{2,4}$/, 张三)); // int(0)按字节算有 6 个「字符」var_dump(preg_match(/^.{2,4}$/u, 张三)); // int(1)按字符算正好 2 个处理中文时请一律加上u并且要用 Unicode 属性转义如\p{Han}表示汉字、\p{L}表示任意语言的字母来描述字符类别不要指望\w会覆盖非 ASCII 字符。二、模式语法速查下面这份速查表覆盖了日常九成以上的需求. 除换行外的任意字符加 s 修饰符后含换行^ $ 行首 / 行尾加 m 后按行计算\d \D 数字 / 非数字\w \W 单词字符字母、数字、下划线/ 非单词字符\s \S 空白字符 / 非空白字符[abc] 字符类匹配其中任意一个[^abc] 反向字符类匹配不在其中的任意一个[a-z0-9] 字符区间* ? 0 次以上 / 1 次以上 / 0 或 1 次贪婪*? ? ?? 对应的懒惰版本尽量少匹配* ? 占有版本匹配后不回退{n} {n,} {n,m} 精确 n 次 / 至少 n 次 / n 到 m 次(...) 捕获组(?:...) 非捕获组只分组不占用编号(?Pname...) 命名捕获组等价的尖括号写法现代 PCRE 也支持\1 \kname 反向引用引用之前捕获到的内容(?...) 正向前瞻断言右侧必须符合但不消耗字符(?!...) 负向前瞻断言(?...) 正向后顾断言(?!...) 负向后顾断言a|b 分支匹配 a 或 b\b \B 单词边界 / 非单词边界\p{Han} 汉字需加 u 修饰符几点使用提示非捕获组能不用编号就别占用编号。(?:...)不产生捕获既省内存也让$matches的下标清晰。后顾断言要求定长或有限长度。这是 PCRE 的硬性限制带长度区间的后顾写法在部分场景下不被接受写之前先确认模式的定长性。x修饰符适合写长模式它忽略模式里的空白于是可以换行缩进、加注释可读性大幅提升。POSIX 时代的写法与现在的对应关系也整理一份方便迁移旧代码已移除的写法现在的等价写法ereg($p, $s)preg_match(/ . $p . /, $s)eregi($p, $s)preg_match(/ . $p . /i, $s)ereg_replace($p, $r, $s)preg_replace(/ . $p . /, $r, $s)split(,, $s)explode(,, $s)或preg_split(/,/, $s)sql_regcase()无对应需要时自行构造注意 POSIX 的字符类写法[[:alpha:]]、[[:digit:]]在 PCRE 里仍然可用它们和\w、\d不是一回事迁移时不用一起改掉。另外旧代码里常见的preg_replace()加e修饰符也在 PHP 5.5 被废弃、PHP 7.0 被移除正确做法是改用preg_replace_callback()。三、捕获组、断言与回溯preg_match()一次只找第一个匹配它的第三个参数是按引用传入的数组用来接收捕获结果。下标 0 是完整匹配1 开始依次是各捕获组?php // 适用于 PHP 8.0$pattern /^(\d{4})-(\d{2})-(\d{2})$/;$subject 2026-10-06;$result preg_match($pattern, $subject, $matches);var_dump($result); // int(1)echo $matches[1], 年, $matches[2], 月, $matches[3], 日, PHP_EOL;带名字的捕获组更好读但要注意它在结果数组里会出现两次——一次用名字做键一次用序号做键?php // 适用于 PHP 8.0$pattern /^(?year\d{4})-(?month\d{2})-(?day\d{2})$/;if (preg_match($pattern, 2026-10-06, $m) 1) {echo $m[year], -, $m[month], -, $m[day], PHP_EOL;echo $m[1], -, $m[2], -, $m[3], PHP_EOL; // 同一批值换个键取}断言assertion用来描述「匹配位置周围必须满足什么条件」但它不消耗字符所以不会出现在$matches里。它是替代「先匹配一大段再手工裁剪」的好工具?php // 适用于 PHP 8.0$text 价格 100 元折扣 20 元;// 只取后面紧跟「 元」的数字但不把「元」匹配进来preg_match_all(/\d(? 元)/, $text, $prices);echo implode(,, $prices[0]), PHP_EOL; // 100,20最后说性能。PCRE 使用回溯backtracking算法模式写不好会导致「回溯爆炸」引擎尝试了指数级的组合才判定失败CPU 被吃满。核心原因是嵌套量词——形如「一个量词修饰的组里又含量词」的模式在不匹配的长输入上代价极高。防御手段有三条能写精确就写精确例如限定内容的字符类和明确的长度范围。用占有量词*、、?告诉引擎「匹配到就不用回头」它对不需要回退的场景完全等价于贪婪量词。在进程层面设防pcre.backtrack_limit和pcre.recursion_limit这两个 ini 配置决定了回溯的上限超出后preg_*会返回false而不是一直算下去。第三条尤其重要因为回溯超限返回的是false不是0。如果代码写的是「没匹配上就报格式错误」回溯超限会被误报成「格式不对」把一个性能问题伪装成业务问题。?php // 适用于 PHP 8.0// 出错时用 preg_last_error_msg() 看原因需要 PHP 8.0PHP 7 用 preg_last_error() 拿错误码$ok preg_match(/\d/, abc);var_dump($ok); // int(0)真的没匹配上var_dump($ok false); // bool(false)说明这不是错误常见坑点❌ 用ereg()、eregi()、split()的旧代码直接上线。✅ 这些函数在 PHP 5.3 废弃、PHP 7.0 移除改用preg_match()、preg_match()加i修饰符、preg_split()或explode()。❌ 用preg_replace()的e修饰符执行替换结果。✅ 该修饰符 PHP 5.5 废弃、PHP 7.0 移除应改用preg_replace_callback()显式回调。❌ 处理中文时不加u修饰符。✅ 不加u时点号和量词都按字节算一个汉字占 3 字节长度判断会整体错位。❌ 用\w去匹配中文以为它会包含所有语言的字母。✅\w默认面向 ASCII匹配汉字请用\p{Han}匹配任意字母用\p{L}并且都要加u。❌ 把模式写进单引号字符串时忘了处理反斜杠。✅ 单引号里\d就是\d本身问题不大但\\d会变成字面量反斜杠加 d写模式时统一用单引号并只写一次反斜杠最不容易错。❌ 用正则去完整校验邮箱或日期的语义合法性。✅ 正则只适合做形状粗筛邮箱用filter_var()加FILTER_VALIDATE_EMAIL日期合法性用DateTime::createFromFormat()校验。❌ 写出嵌套量词的模式并用它去处理用户提交的长文本。✅ 嵌套量词容易引发回溯爆炸长输入下 CPU 飙高改用精确字符类、占有量词并给pcre.backtrack_limit设一个合理上限。❌ 把回溯超限返回的false当成「没匹配上」。✅false表示出错0才表示没匹配判断命中请写 1并在失败分支里检查preg_last_error()/preg_last_error_msg()。总结关注点结论现行扩展只有 PCRE 系的preg_*POSIX 的ereg_*在 PHP 7.0 已移除定界符任意非字母数字非反斜杠非空白的字符斜杠、井号、波浪号最常用必加修饰符处理中文一定要加u捕获组(...)捕获并占编号(?:...)只分组断言前瞻断言与后顾断言各自都有否定形式都不消耗字符错误与未命中出错返回false未命中返回0必须用区分性能红线嵌套量词会引发回溯爆炸靠精确模式、占有量词、回溯上限三重设防该交给别人的活邮箱、日期的语义校验不要用正则硬扛学 PHP 正则最省事的路径是先把「定界符 修饰符 u」这三件事形成肌肉记忆再记牢「false是错误、0是没匹配」这条判断规则剩下的语法细节随用随查即可。真正会让人栽跟头的从来不是记不住元字符而是把回溯爆炸和语义校验这两类问题错误地交给了正则。

相关新闻

php框架Phpbean说明

php框架Phpbean说明

前言 先说清楚一件事:Phpbean 是一个非常早期(PHP 5 时代)的轻量级 MVC 框架,早已停止维护,它的官方站点和官方文档如今都很难找到。网上关于它的说明文章内容高度雷同,基本是同一份文本被反复转抄&#xf…

2026/10/9 9:54:17 阅读更多 →
Honeywell EPKS SafeView配置实战:只读视图安全加固指南

Honeywell EPKS SafeView配置实战:只读视图安全加固指南

简介:本资源是一份面向工业自动化领域DCS操作员与系统工程师的Honeywell EPKS SafeView专项技术指南,聚焦解决传统Windows多窗口环境在工业监控场景中画面混乱、关键信息易被覆盖、操作不可控等核心痛点。文档基于Honeywell官方标准文档(如GS…

2026/10/9 9:54:17 阅读更多 →
从信息到Element:WSaiOS-SI结构智能体系的信息结构化理论研究

从信息到Element:WSaiOS-SI结构智能体系的信息结构化理论研究

从信息到Element:WSaiOS-SI结构智能体系的信息结构化理论研究摘要:信息如何进入结构智能体系,是WSaiOS-SI理论建设中必须回答的基础问题。本文提出,信息不等于Element,字符不等于Element,Token不等于Elemen…

2026/10/9 9:54:17 阅读更多 →

最新新闻

多模态无监督持续后训练:视觉依赖感知框架解析

多模态无监督持续后训练:视觉依赖感知框架解析

多模态模型的持续更新一直有个很现实的问题:新数据来了,直接继续训练容易忘掉旧能力;不做训练,新场景又用不上。如果数据还没有人工标注,问题会更麻烦。这次我们看的这个框架,名字叫A Visual Dependence-Aw…

2026/10/9 10:33:01 阅读更多 →
SpringBoot+SpringCloud电商源码实战:微服务启动顺序与避坑指南

SpringBoot+SpringCloud电商源码实战:微服务启动顺序与避坑指南

简介:这是一套面向计算机相关专业在校学生与教师的电商系统课程设计/毕业设计源码包,基于Spring Boot与Spring Cloud构建,采用Spring Security、MyBatis、Redis、Docker、Elasticsearch等技术栈,并运用分布式微服务架构&#xff0…

2026/10/9 10:33:01 阅读更多 →
惠普战66拔掉耳机后扬声器无声

惠普战66拔掉耳机后扬声器无声

机型 HP ZHAN 66 Pro A 14 G4 | Windows 10 | 声卡 Realtek ALC236帖主的问题最终还是借助 Cursor 得以修复,下附 Cursor 总结的具体的问题表现、排查过程及结论,供有需要的同仁参考。一、问题描述耳机插上以后,声音正常。耳机拔掉以后&a…

2026/10/9 10:33:01 阅读更多 →
从临时Subagent到持久化AI团队:状态恢复与审计追踪设计

从临时Subagent到持久化AI团队:状态恢复与审计追踪设计

这次我们来看一个很有意思的项目:Show HN: Turn ad-hoc subagents into durable, accountable AI teams。从标题就能看出,它解决的不是“再做一个 Agent”,而是更现实的问题:平时随手创建的临时 Subagent 一到任务结束就丢了&…

2026/10/9 10:33:01 阅读更多 →
RIGOL DS1000系列LabVIEW驱动实战:从RS232/GPIB通信到自动化测试集成

RIGOL DS1000系列LabVIEW驱动实战:从RS232/GPIB通信到自动化测试集成

简介:这份资源面向使用普源DS1000系列示波器、希望借助LabVIEW实现远程控制与数据采集的工程师与测试人员,重点解决RS232串行通信和GPIB总线两种接口下的驱动调用问题。压缩包共54个文件,约570KB,以42个vi虚拟仪器文件为核心&…

2026/10/9 10:33:01 阅读更多 →
图书馆预约系统小程序源码拆解:Java+微信小程序+MySQL三层架构

图书馆预约系统小程序源码拆解:Java+微信小程序+MySQL三层架构

简介:这是一套基于微信小程序的图书馆预约系统毕业设计项目,面向计算机相关专业学生,适用于毕业设计或课程设计场景。系统采用微信小程序开发工具、MySQL数据库与Java的B/S架构实现,完整覆盖管理员、用户、员工三类角色&#xff1…

2026/10/9 10:32:00 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 10:11:06 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 6:17:20 阅读更多 →