程序员圈子里流传一个老段子:「有些人遇到问题时会想,我知道,我用正则表达式。于是他们有了两个问题。」这句话出自 Netscape 早期工程师 Jamie Zawinski 之口,被调侃了几十年,却恰恰证明了一件事:正则这门手艺,人人绕不开,人人头疼过。Fireship(主理人 Jeff Delaney)的《Regular Expressions (Regex) in 100 Seconds》就是把这门手艺浓缩进一百秒的爆款课——上线后播放量达到数百万级(历史公开数据,本次未能实时核实,发布前建议复核),成为无数开发者正则入门的第一站。本文把它当作「目录页」展开成整本书:视频到底讲了什么、这些稀奇古怪的符号从哪来、引擎底层怎么跑、以及它没讲的那条暗坑,如何在 2019 年放倒过半个互联网。
| 项目 | 内容 |
|---|---|
| 视频标题 | Regular Expressions (Regex) in 100 Seconds(正则表达式一百秒速成) |
| 频道 | Fireship(主理人 Jeff Delaney,以「in 100 Seconds」系列与前端圈辣评闻名) |
| 上线时间 | 2019 年前后,属其「in 100 Seconds」系列走红期(据频道页面归档) |
| 播放量 | 数百万级(历史公开数据,未能实时核实) |
| 定位 | 入门速览:语法地图 + 现场代码演示 |
| 时长 | 约 2 分钟 |
视频开场就把定位讲死:正则不是一门编程语言,而是用一串字符描述一个搜索模式的迷你语言(视频复述)。你写下的不是「匹配某个具体字符串」的代码,而是「某一类字符串的共同形状」。比如 \d{3}-\d{4} 描述的不是某一个电话号码,而是「三位的段、一根横杠、四位的段」这一整族号码。
我的延伸分析:这条定义里藏着正则难学的真正原因——它是叠在另一层语言之上的语言。普通字符(字面量)和元字符(控制符)混写在同一行里,同一个符号在不同位置身份不同:a 就是字母 a,. 却是「任意字符」,而 `.又变回了句号本身。这种「一符多义、上下文定身份」的设计,是它表达力恐怖的来源,也是它可读性灾难的根源。
视频主体是一条极快的现场演示,把语法拆成四组依次亮相(视频复述,个别顺序据画面):
\d 匹配数字,\w 匹配字母数字下划线,\s 匹配空白;方括号自定义集合 [a-zA-Z0-9],方括号里开头放尖号 [^0-9] 表示「取反,匹配非数字」;* 零个及以上,+ 一个及以上,? 可有可无,{2,4} 指定重复两到四次;^ 锚定行首,$ 锚定行尾,\b 锚定单词边界——锚点不消耗字符,只声明位置;() 捕获子串供后续提取,竖线 | 表示「或」,(?:...) 只分组不捕获,节省内存也少生噪音。最后补了两个「改行为」的旗标:g 全局匹配(否则只命中第一处),i 忽略大小写,m 把 ^ $ 的语义从整串扩展到每一行。
我的延伸分析:这张地图的精妙之处在于正交——四件套可以自由组合,一个模式 = 字符类回答「匹配什么」,量词回答「重复几次」,锚点回答「在哪匹配」,分组回答「怎么切出我要的部分」。学会这四件的组合思维,比背一百条实例正则更根本。
视频用 JavaScript 做演示:字面量 /pattern/flags 直接书写,RegExp 构造器动态创建,.test() 返回布尔判断,.match() 提取命中结果(视频复述)。
我的延伸分析:选 JS 不是随意的——正则字面量在 JS 里是语言级一等公民,不需要像 Java 那样写双重转义的地狱字符串。但这也埋了个坑:不同语言里正则的「方言差异」真实存在。Python 的 re、Java 的 java.util.regex、PCRE、Go 的 regexp,语法八成相似,剩下两成(贪婪策略细节、Unicode 支持、是否支持反向引用与环视)各有各的脾气。「学会语法」和「用好正则」之间,隔着的正是这层方言意识。
视频收尾强调正则「几乎所有语言、几乎所有编辑器、几乎所有工具链都支持」,值得每个开发者投入(视频复述)——同时也没忘记自嘲那句 two problems 的圈著名梗。
我的延伸分析:这个收尾其实是全片最诚实的一分钟。正则的最佳射程是模式清晰、规模有限、一次性的文本任务:日志抽取、格式校验、编辑器批量替换。一旦模式复杂到需要写注释才有人读懂,或者要处理「理论上无限长」的输入,就该考虑换成普通代码——可读性是生产环境里比简洁更贵的货币。
正则比个人电脑还年长三十岁,它的家谱每一段都是硬历史:
换句话说,你在视频里看到的 \d 和 *,是一条从神经生理学数学、经贝尔实验室、到万维网基础设施的七十年传承线。
视频完全没展开、但决定正则生死的,是引擎层:
re、JavaScript、Java、.NET、PCRE 默认走的路。实现直观、功能全(支持反向引用、环视这类自动机表达不了的功能),代价是性能最坏情况指数级;regex crate、Go 标准库 regexp。不回溯,保证线性时间,代价是砍掉反向引用等特性;视频省略的那条暗坑,有一个教科书级的事故现场。据 Cloudflare 官方事后报告:2019 年 7 月 2 日,一条用于 XSS 防护的 WAF(Web 应用防火墙)规则带着嵌套量词的正则上线,在 PCRE2 的回溯引擎上触发灾难性回溯(catastrophic backtracking),全球边缘节点 CPU 被打满,全站大面积返回 502,宕机持续约 27 分钟,波及大量依赖其反代的网站。CTO John Graham-Cumming 发布了详细事后报告,事故后 Cloudflare 的新一代 WAF 引擎改用了 Rust 的线性时间正则库——据其官方博客。
这条暗坑学名 ReDoS(Regular expression Denial of Service),已收入 OWASP 词条。经典触发样例是用模式 ^(a+)+$ 去匹配一长串 a 加一个失败结尾:回溯引擎会把所有分组切分方式试个遍,二十几个字符就能把耗时推到天文数字。无独有偶,2016 年 Stack Overflow 的一次宕机,官方事后也归因于一条失控的正则(据其官方复盘)。
Regex 支持 matchTimeout,PCRE2 有 match limit)。这一条习惯,价值超过一百条语法技巧。flowchart TD
A["正则表达式<br/>文本匹配迷你语言"] --> B["语法层:四件套"]
A --> C["理论层:正则语言"]
B --> B1["字符类与量词"]
B --> B2["锚点/分组/旗标"]
C --> C1["Kleene 1956<br/>正则概念诞生"]
C --> C2["Thompson 1968<br/>编译成机器码"]
C1 --> D["两种引擎路线"]
C2 --> D
D --> E["回溯引擎<br/>PCRE/Python/JS"]
D --> F["自动机引擎<br/>RE2/Rust/Go"]
E --> G{"嵌套量词<br/>+不可信输入?"}
G -->|"是"| H["灾难性回溯"]
H --> I["ReDoS事故<br/>Cloudflare 2019"]
G -->|"否"| J["正常匹配"]
F --> K["线性时间保证"]
本文由「51学通信」技术团队出品。51学通信由通信行业18年老兵爱卫生(微信ID: gprshome201101)维护,聚焦5G/6G核心网、3GPP标准解读、通信前沿技术深度分析。 出版作品有《5G核心网原理与实践》《IMS原理与实践》等4本通信专业书籍。知识星球「51学通信」提供深度技术答疑和行业洞察。
[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。
