正则表达式是什么:一次学习,处处可用

从"找字"到"找模式"

假设你手里有一份两万行的订单日志,老板问:把所有形如 DD20241026001873 的订单号都捞出来。用肉眼搜?搜索框里输入 DD 只能定位第一处。这时你需要描述的不是某个具体的字符串,而是一类字符串的共同形状:DD 开头、后面跟 12 位数字。这个"形状的描述",就是正则表达式(Regular Expression,常简写为 regex 或 regexp)。

换一种更正式的说法:正则表达式是一门微型的模式描述语言。普通搜索回答"文件里有没有这个词",正则回答"文件里有没有符合这个规则的字符串"。前者是字面量的世界,后者是结构的世界。从"字符级思维"切换到"模式级思维",是学习正则要过的第一道心理关。

# 目标:从日志里捞出所有订单号
import re
line = "10:21:07 用户 u_8817 下单成功 订单号 DD202410260018 金额 199.00"
print(re.findall(r"DD\d{12}", line))
# 输出:['DD202410260018']

一行 DD\d{12}:DD 是字面量,\d 表示"任意一个数字字符",{12} 表示"前面的东西重复 12 次"。每个符号都有明确职责,组合起来就是一条可执行的筛选规则。

它藏在你每天用的工具里

很多开发者觉得自己"没学过正则",实际上早就被它包围了。你在编辑器里按 Ctrl+F 勾选正则开关、在终端里敲 grep、在 Nginx 配置里写 location ~ \.php$、在 Excel 里做高级筛选——背后都是同一套模式语言。

  • 命令行:grep、sed、awk 三剑客的正则是文本处理的母语,任何 Unix 服务器上都躲不开。
  • 编辑器:VS Code、JetBrains 系列、HBuilderX 的查找替换都支持正则模式,批量改代码全靠它。
  • 编程语言:JavaScript 的 RegExp、Python 的 re 模块、Java 的 java.util.regex、Go 的 regexp(RE2 引擎)。
  • 中间件与平台:Nginx/Apache 的路由匹配、日志采集(Filebeat、Fluentd)的行解析、CI 里过滤文件路径、Kibana 的查询语法。

同一个模式 ^\d{4}-\d{2}-\d{2}$,在 Python 里校验输入是否为日期格式,在 grep 里过滤日志行,在编辑器里批量定位时间戳,写法几乎一样:

# 在 access.log 中找出所有以日期开头的行
grep -E '^\d{4}-\d{2}-\d{2}' access.log      # 注意:grep 默认不认 \d,实际应写 [0-9],详见第三章
grep -E '^[0-9]{4}-[0-9]{2}-[0-9]{2}' access.log

这就是"一次学习,处处可用"的含义:核心概念高度统一,只是方言略有差异。学会一次,你相当于同时解锁了十几类工具的高级功能,这是性价比极高的一项技能。

方言确实存在,但骨架一致

强调"处处可用"的同时,也要诚实地承认差异。正则有许多流派(flavor):Perl 系(PCRE)功能最全,JavaScript、Python、Java 大体跟随它;Go 使用的 RE2 出于性能考虑砍掉了回溯与环视;老牌 Unix 工具还保留着 BRE/ERE 两套古董语法。差异集中在少数高级特性上,而字符组、量词、锚点、分组这四大件在所有方言里几乎一致。

能力 JavaScript Python Java Go(RE2) grep -E
字符组 [a-z]、\d 支持 支持 支持 支持 \d 需换 [0-9]
命名分组 (?<名>) (?P<名>) (?<名>) (?P<名>) 不支持
环视断言 支持 支持 支持 不支持 不支持(-P 除外)
反向引用 \1 支持 支持 支持 不支持 支持
忽略大小写标志 i re.I CASE_INSENSITIVE (?i) -i

本书的策略是:先用第一章到第二章把统一骨架学扎实,第三章再逐方言对照差异。这样你不会陷入"每个语言重学一遍"的错觉,也避免把 A 方言的特性误用到 B 方言里。

正则擅长什么,不擅长什么

它是文本的手术刀,但不是万能钥匙。判断要不要用正则,可以用下面三条标准:

  1. 目标有稳定可描述的结构:订单号、IP 地址、日志行格式、HTML 标签的粗筛,都适合。
  2. 规则是"形状"而非"语义":正则能判断"看起来像邮箱",判断不了"这个邮箱真的能收信"。
  3. 文本量与嵌套深度可控:解析任意嵌套的 JSON/XML、处理成 HTML 文档树,应该用专门的解析器,正则只做粗筛或善后。

避坑提醒:初学者最常见的弯路是"正则万能论"——试图用一个巨型正则解析整份 HTML 或完整 JSON。记住业界那句老话的意译版:结构化数据交给解析器,正则负责边缘的琐碎。用正则从 HTML 里抠一个 title 字段没问题,用它重建整棵 DOM 就是在给自己埋雷。

学完本书你能做什么

  • 从任意日志中提取 IP、时间、状态码,做一次像样的流量分析;
  • 三分钟批量重命名一百个文件、清理一段代码里的注释;
  • 写出能通过测试的表单校验,而不是网上复制来、连自己都不敢保证对的那一条;
  • 识别并修复一个可能拖垮服务的回溯灾难。

正则的学习曲线前缓后陡:入门只需记住十几个符号,精通则要理解引擎的匹配机制。好消息是,日常工作中 80% 的场景只用到入门那部分。本书会带你把常用的练到肌肉记忆,把进阶的讲到看得懂、查得到,让你在"够用"和"精通"之间进退自如。

一分钟自测:这段文本该用什么工具

学完本章,先做三个真实任务的判断题,练一练"要不要上正则"的直觉:

  • 任务 A:把配置文件里所有 host=旧地址 批量改成新地址——用正则。结构扁平、模式稳定,一条替换命令搞定。
  • 任务 B:判断用户提交的一段 JSON 是否合法——不用正则。交给解析器,它连"多了一个尾逗号"都能精确报错,正则只会给你似是而非的答案。
  • 任务 C:统计一万行日志里 404 出现的次数——正则加管道。正则负责认出状态码,计数、排序交给后续工具。
import re
line = '10.0.0.7 - "GET /a" 404, 10.0.0.8 - "GET /b" 404'
print(len(re.findall(r"\b404\b", line)))
# 输出:2

\b404\b 带着边界扫描整行,命中两次——判断"要不要用正则"之后,第二步永远是"正则负责其中哪一小段"。三个任务对应的三种答案,就是本书反复出现的分工原则:正则做模式识别,结构化解析做结构验证,统计汇总交给宿主语言。

四种角色的正则日常

  • 后端:参数校验、日志解析、灰度规则里的路径匹配,几乎每个服务都藏着几条正则。
  • 前端:表单校验、路由匹配、从富文本里抽摘要,正则频率不低于后端。
  • 运维:日志审计、配置批量修改、监控告警规则,正则是 shell 脚本的呼吸。
  • 数据:字段清洗、脏数据拦截、文本特征抽取,一条好正则省一个 ETL 环节。

角色不同,场景不同,但底座是同一套语言。这也是本书坚持"先通用机制、后方言差异"的原因:底座打牢,换任何场景都只是换词汇表。

三个高频疑问,先答为敬

问:正则难学吗?要多久能干活? 难度分布是"前 10% 的符号解决 80% 的问题"。字符组、量词、锚点、分组四件套,认真学一周就能处理日常文本任务;环视、回溯这些进阶机制,等真实需求来了再深入也不迟——本书的章节顺序就是按这个规律排的。

问:要不要背元字符表? 不用背清单,要背例句。记 DD\d{12} 比记"\d 匹配数字"有效得多——例句自带上下文,考试式的符号表背完就忘。本书每章的代码块都是为你准备的例句库。

问:正则会被 AI 工具取代吗? 生成一条正则越来越容易,但判断生成的正则对不对、快不快、会不会被特殊输入打爆,仍然需要人懂机制。学这本书不是学"怎么写",更是学"怎么审"——这项能力短期内没有替代品。

带着这三个答案往下读,你会对每一章的详略安排更有感觉:写法从简,机制从详。

最后给一个学习节奏建议:第一遍通读时,允许自己对第三、四章的配方只看不练;第二遍带着真实需求回来精读对应章节。正则知识的最佳巩固时机是刚好要用的那一刻——把本书当工具书用第二遍,价值远大于一口气精读五遍。

参考资源

本章由 WorkBuddy 原创撰写,示例均经实际验证。