在编程世界里,有一门技能几乎人人用过、人人怕过、人人骂过,却谁也离不开它——正则表达式(Regular Expression,简称 regex)。YouTube 上知识类频道 Fireship 的《Regex in 100 Seconds》正是把这门“黑白魔法”压缩进两分钟的神课:节奏极快、信息密度极高,评论区常年是一边“我看了五遍才消化”一边“这是我唯一看懂的正则入门”的两极景观。它常青的原因很朴素:只要你还需要处理文本——验证表单、解析日志、清洗数据、改配置——你就迟早会和正则狭路相逢。
但两分钟只能给你一张“地图”,不能给你“地形”。这篇文章的任务,是把这条视频里的每一句话拆开、放慢、溯源、批判:正则从哪里来(它其实是一门被数学定义过的语言)、它的两个引擎为什么性能天差地别、为什么它既是程序员的最爱又是生产事故的常客。看完本文,你没看过视频也能懂;看过视频,你会多懂一整层。
| 项目 | 内容 |
|---|---|
| 视频标题 | Regex in 100 Seconds(100秒讲完正则表达式) |
| 频道 | Fireship(主理人 Jeff Delaney) |
| 发布时间 | 2020年12月前后(据频道页面) |
| 播放量 | 数百万级,为其“100秒”系列常青头部(据频道页面,未实时核验精确数字) |
| 时长 | 约2分钟 |
| 观看渠道 | YouTube 检索 "Fireship Regex in 100 Seconds",或访问其官方频道页 |
(注:以上数据以频道页面公开信息为准,本文无法实时核验精确播放量,故只标注量级。)
这条视频的叙事结构极其紧凑,本质上是一堂“从零到能写”的速成课。按镜头顺序拆开,它讲了五层内容。
视频开宗明义:正则表达式是一种用符号描述文本模式的微型语言。它不是某家公司的产品,也不是某个库的 API,而是一种横跨几乎所有编程语言的通用记法。你写下 ^\d{3}-\d{4}$,任何语言都能读懂这句话:“以三个数字开头、中间一个连字符、后面跟四个数字、然后结束。”
视频在这里埋了一个重要的认知锚点:正则解决的不是“查找某个字符串”,而是“查找一类字符串”。前者用 Ctrl+F 就够了,后者才是正则存在的理由。这也是它难的根源——你从“字面思维”切换到“模式思维”,等于换了一种世界观。
接下来视频快速演示了基础积木:普通字符按字面匹配;方括号 [abc] 表示“这个位置可以是 a、b 或 c”;\d 代表任意数字,\w 代表字母数字下划线,. 代表任意单个字符。这一层的要点是:正则的每个符号都在回答一个问题——“下一个字符长什么样”。把正则读对的方法,是从左到右逐位“过筛子”,而不是把它当一个整体去猜。
然后是威力最大的部分:量词。* 表示零次或多次,+ 表示一次或多次,? 表示零次或一次,{2,5} 表示两次到五次。视频在这里出现了一个几乎所有初学者都会踩、但两分钟课程没时间展开的深坑——贪婪匹配:默认情况下量词会“吃掉尽可能多”的字符,想让它“吃少一点”,要在量词后面加问号变成懒惰模式。<.*> 和 <.*?> 在解析 HTML 时会给出完全不同的结果。这个加号后的小问号,是新手与老手写出的正则最常见的一处分水岭。
量词解决“重复”,锚点解决“位置”:^ 锚定行首,$ 锚定行尾,\b 锚定单词边界。分组用圆括号实现,除了把几个符号捆成一个整体,还能“捕获”匹配内容供后续引用,配合 | 实现“或”的分支。至此,视频已经拼出了完整的能力图谱:字符描述内容,量词描述重复,锚点描述位置,分组描述结构。
最后视频亮出了高级技能——环视断言(lookahead / lookbehind):只匹配“后面跟着 XX”的位置,却不把 XX 吃进结果。然后给出了正则的三大典型战场:表单验证(邮箱、手机号)、搜索替换(编辑器里的批量改写)、日志与数据的抽取清洗。结尾不忘安利两个神器:regex101 这类在线调试工具(实时高亮、逐条解释每个符号)和“别背语法、要用时现查”的实用主义态度。
两分钟的视频当然没时间讲历史,但正则的每个符号背后都站着真实的人和论文。这一节是本文要给你的“多懂的一层”。
正则不是程序员发明的,是数学家发明的。1951年,美国兰德公司(RAND)的数学家斯蒂芬·科尔·克莱尼(Stephen Cole Kleene)在研究神经网络建模时,提出了一类可以用极简规则描述的“正则事件”(regular events),后于1956年发表为论文《Representation of Events in Nerve Nets and Finite Automata》。他证明了:这类语言恰好等于有限自动机所能识别的语言。这个等价关系是整个正则帝国的地基——你在键盘上敲的每个 * 和 +,都是一个数学对象。
真正让正则“飞入寻常百姓家”的是 Unix 传奇肯·汤普森(Ken Thompson)。1968年,他在 CACM 发表论文《Regular Expression Search Algorithm》,给出了把正则编译成 IBM 7094 机器码的高效实现,并把它做进了 QED 编辑器。随后在贝尔实验室的 ed 编辑器里,搜索命令的用法是“全局(global)搜索正则表达式(regular expression)并打印(print)结果”——这个命令的缩写 g/re/p,就是日后命令行神器 grep 的名字。你在终端里敲下的每一次 grep,都是在向 1968 年的贝尔实验室致敬。
正则随后随 Unix 扩散,但也开始了几十年的“方言分裂”:POSIX 定义了基础正则(BRE)与扩展正则(ERE)两套标准;Perl 横空出世后加入大量糖衣与高级特性,形成了事实上的 PCRE(Perl Compatible Regular Expressions)流派;JavaScript、Python、Java、.NET 各自实现了“大致像 Perl 但各有出入”的版本。同一条正则,换一个语言可能语义就变——这正是视频里“别背语法、用时查工具”态度背后的历史原因:不是你不努力,是这门语言确实没有唯一标准。
这是理解正则性能的钥匙,也是视频中完全没讲、但任何在生产环境用过正则的人都该懂的一层。实现正则的引擎分两大流派:
2010年前后,谷歌工程师拉斯·考克斯(Russ Cox)在 swtch.com 发表的著名三部曲《Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby...)》系统梳理了这段历史:Thompson 1968 年的算法本来就是线性的,后来的主流语言却普遍选择了容易实现高级功能的回溯路线,等于在性能上“开倒车”。这篇文章是正则领域被引用最多的工程文献之一。
理论爆炸是真的会炸的。2016年7月,Stack Overflow 因一条性能问题正则在负载评估环节触发灾难性回溯,页面大面积不可用,事后官方复盘公开了全过程;2019年7月2日,Cloudflare 全球边缘网络因一条正则(内含嵌套量词叠加的病态模式)导致边缘节点 CPU 打满,接近全网宕机约27分钟,其官方博客以《Details of the Cloudflare outage on July 2, 2019》做了极其坦诚的复盘。两次事故的模式高度一致:一条“在测试数据上跑得好好的”的正则,遇到某段“恰好恶意”的输入,回溯次数指数级增长,CPU 瞬间归零可用性。这类攻击有个专门的名字:ReDoS(Regular Expression Denial of Service,正则拒绝服务)。
视频对正则语法的讲解本身零瑕疵——字符类、量词、锚点、分组、断言的表述全部准确,这是 Fireship 一贯的工程严谨度。“用 regex101 调试”的建议也完全正确:正则是典型的“看会了≠会写”技能,逐符号可视化反馈是最高效的学习路径,这个建议值得再加倍强调。
100秒课程最大的取舍,是只教“怎么写”,没教“引擎怎么读”。而上面两起宕机事故证明:只会写、不懂引擎,等于拿着能走火的工具不知道枪里有没有子弹。(a+)+b 这种嵌套量词模式,对普通输入毫无异样,对一串 "aaaaaaaaaaaaaaaaaaaaX" 却会让回溯型引擎卡到天荒地老——同一份代码,换个输入就是事故。这不是初学者才需要的知识,而是每一个把正则投放到生产环境的人的必修课。
视频把邮箱验证作为典型场景,但没说的是:“用一条正则完美验证邮箱”本身就是社区里被嘲笑了二十年的经典陷阱。RFC 5322 定义的合法邮箱地址复杂到理论上需要递归才能完全描述;业界共识早已是“用一条宽松正则做初筛 + 发送确认邮件做真验证”。程序员圈流传的名言出自 Netscape 早期工程师 Jamie Zawinski:
“有些人遇到问题时想:‘我知道,我用正则吧。’现在他们有两个问题了。”
xkcd 漫画也曾专门调侃“用正则解析 HTML”的自噬行为。这些调侃的共同内核是:正则适合正则语言层面的任务,一旦任务涉及任意深度的嵌套结构(HTML、JSON、配对括号),正则在理论上就注定力不从心——这又要回到 Kleene 的等价性定理:有限自动机没有栈,数不了括号层数。你嘲笑的每个“正则解析 HTML”的段子,其实都是 1956 年那篇数学论文早已证明的定理。
大量“正则恐惧症”来自可读性差的超长正则。但工程实践里有一条被低估的纪律:正则的复杂度应该被控制在“一眼能读”的范围内,超出的部分应该拆成多条简单正则加普通代码,或者直接用字符串 API(split、indexOf、模板匹配)解决。社区 surveys 中“程序员最怕的正则”大多是人祸——把三百个业务规则硬塞进一条模式。正则不是用来炫技的一行流,是用来消灭重复样板代码的工具;当它开始制造样板般的晦涩时,就该退场了。
看懂一条复杂正则的秘诀,是把“模式”翻译成“状态流转”:我从行首出发,此刻期待什么字符,吃到它之后进入什么状态,什么情况宣告失败。下次面对一条看不懂的正则,别整段盯着看,用 regex101 的高亮逐步喂样例字符串,观察哪些位置点亮、哪些位置熄灭——你实际上是在观察一台自动机的运转。理解从“背符号”升级为“走状态”,正则就从咒语变成了透明的机器。
给自己立一条工程铁律:凡是用在服务端、处理不可信输入的正则,写完后必须做两件事——第一,检查是否存在嵌套量词((a+)+、(a|a)*、(.*)* 这类结构);第二,用超长重复样本压测一遍耗时。如果你的语言/运行时有条件,优先选择线性引擎:Go 的 regexp、Rust 的 regex、谷歌 RE2 天生免疫 ReDoS;必须用回溯引擎时,把匹配调用放进超时保护里。Cloudflare 那条炸掉半个边缘网络的正则,上线前没人觉得它会出事。
正则最甜的场景有三类:格式明确的短文本验证(日期、编号、版本号)、编辑器与命令行里的批量搜索替换(一次顶一小时手工)、日志与数据的结构抽取(配合分组捕获)。超出这三类的诱惑——解析 HTML、校验复杂业务规则、“一行搞定”的炫技——都先问自己一句:普通代码是不是更清楚?可读性是团队资产,一行别人看不懂的“优雅”正则是团队负债。
flowchart TD
A["Kleene 正则集<br/>1951"] --> B["Thompson 塞进编辑器<br/>1968"]
B --> C["grep 诞生<br/>g/re/p"]
C --> D["方言大分裂<br/>POSIX 与 PCRE"]
D --> E1["回溯引擎<br/>功能多 会爆炸"]
D --> E2["自动机引擎<br/>线性 永不爆炸"]
E1 --> F["嵌套量词<br/>回溯爆炸"]
F --> G["ReDoS 事故<br/>2016 与 2019 两次宕机"]
E2 --> H["RE2 等线性实现<br/>生产安全选项"]
G --> I["三条纪律<br/>查嵌套 压测 限超时"]
(a+)+b 喂进去,亲眼看一次回溯爆炸。本文由「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 等场景全覆盖。
