先交代一个背景:我去年接手过一个日志分析需求,几千行的访问日志要提取 IP、状态码、接口路径,然后按来源统计 TOP 榜单。当时团队里有人准备把日志复制到 Excel 里手动分列,我一听就拦住了——这活儿用正则表达式匹配文本,五分钟就能干完。正则表达式是什么?简单说,它是一种描述“字符串长得像什么样”的语言,用来做文本匹配、提取和替换。无论你是写 Python、Java、JavaScript,还是用 grep、VS Code、Excel,甚至做爬虫、数据清洗、日志分析,正则都是绕不开的核心技能。这篇文章我会从零把匹配原理、语法细节、实战代码、高频报错一路讲透,适合刚接触正则的新手,也适合想系统补漏的老手。
1. 为什么需要正则表达式:核心需求与适用场景
1.1 从一道日常需求说起
很多人第一次接触正则,都是被“从文本里找东西”这件事逼的。举个最简单的例子:给你一百个手机号,有的是 11 位纯数字,有的是 3-4-4 的带横杠格式,有的是 "+86 138xxxx" 开头,你要从中筛出合法的大陆手机号。盯着看一分钟能看出来,但如果是十万条呢?手工筛选根本不现实。
正则表达式的思路是:不关心字符串具体的“内容”,只关心它的“形状”。手机号是“以 1 开头,第二位是 3/5/7/8/9,后面跟着 9 位数字”的结构,那我用 ^1[3-9]\d{9}$ 就能描述这个形状。这就是正则的核心价值——用一套简洁的符号,把“我想找什么形状的文本”表达出来,剩下的交给匹配引擎去扫描。
我经常把正则比作“加强版文件通配符”。Windows 里用 *.txt 找文本文件,* 代表任意多个字符,这是通配符。但通配符太粗糙,它没法说“我要找 3 到 5 个数字”“我要找不是数字的字符”“我要找 URL 里路径部分的第二段”,而正则全都能做到。
1.2 正则表达式的适用边界
正则不是万能的,这点必须先说清楚。它的主战场是这些场景:
- 表单校验:邮箱格式、手机号、身份证号、密码强度。
- 日志分析:从 Nginx、Java、Android 日志中提取时间、IP、错误码。
- 数据清洗:把混在文本里的电话号码、金额、日期抽出来。
- 文本替换:批量把
2023-01-01改成2023/01/01,把 Markdown 图片语法转成 HTML。 - 编辑器批量操作:VS Code、Sublime 里用正则搜索替换,处理几千行带规律的重构。
但如果你要解析 HTML、JSON、XML 这种有嵌套结构的文本,我劝你千万别硬用正则。HTML 的标签可以无限嵌套,正则的“状态记忆”能力有限,写出来的模式往往又长又脆,一个标签属性顺序变化就全盘崩溃。正确的做法是用专门的解析器,比如解析 HTML 用 BeautifulSoup、解析 JSON 用 json.loads。记住这句话:正则适合处理“扁平、有规律”的文本,不适合解析“嵌套树状”的结构。
1.3 和“匹配”概念较个真
现在很多软件里也有“匹配”这个词,比如版图设计工具里的电流镜匹配、OPC UA 配置里的计算机名校验、Excel 里的 VLOOKUP 跨表匹配,以及模板匹配算法。这些“匹配”跟文本正则不是一回事,别混淆。
- 版图电流镜匹配:是模拟电路设计里让晶体管参数一致性的问题,属于几何与电学层面的配比。
- VLOOKUP:是表格数据按关键字关联记录,属于结构化数据查询。
- 模板匹配:是图像处理里用模板图在目标图中找相似区域,属于像素相似度计算。
- 正则匹配:是文本层面按模式串找子串,本质是“模式匹配”。
如果你在搜索引擎里搜“匹配”看到这些词,先分清楚自己要处理的是文本还是图像、是结构化表格还是模拟电路。这篇博文只聊文本正则匹配,但理解这些区别能帮你快速定位工具,省得绕远路。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 正则表达式的核心语法与匹配原理解析
2.1 字符、字符类与元字符
正则的最基础单位是“字符”。你在表达式里写一个 a,它就能匹配文本里的字符 a,这叫做字面量匹配。但要处理复杂的文本形状,光靠字面量不行,于是正则引入了一组“有特殊含义的字符”,叫元字符。
常用的元字符主要有这些:
| 元字符 | 含义 | 示例 |
|---|---|---|
. |
匹配除换行外的任意单个字符 | a.c 匹配 abc、a1c、a c |
^ |
匹配字符串开头 | ^abc 匹配以 abc 开头的字符串 |
$ |
匹配字符串结尾 | abc$ 匹配以 abc 结尾的字符串 |
\d |
匹配一个数字,等价于 [0-9] |
\d\d 匹配两位数 |
\w |
匹配字母、数字、下划线 | \w+ 匹配单词 |
\s |
匹配空白符(空格、制表符、换行) | a\sb 匹配 a b |
\D |
匹配非数字 | \D 匹配 a |
\W |
匹配非字母数字下划线 | \W 匹配 @ |
\S |
匹配非空白符 | \S 匹配 x |
[] |
字符类,匹配括号内任意一个字符 | [abc] 匹配 a 或 b 或 c |
[^] |
否定字符类,匹配括号内没有的字符 | [^0-9] 匹配任意非数字 |
\ |
转义元字符 | \. 匹配字面量点号 |
| |
选择分支,匹配左边或右边 | cat|dog 匹配 cat 或 dog |
字符类特别常用,它允许你更精细地控制字符范围。比如 [a-zA-Z0-9] 表示大小写字母和数字,[a-f] 表示 a 到 f 之间的小写字母。有一个容易踩的坑是减号 - 在字符类里的位置:写在开头或结尾时表示普通横杠,写在中间时才表示范围。想匹配数字或汉字区间,都可以用 [0-9] 和 [\u4e00-\u9fa5] 这样的写法。
(\u4e00-\u9fa5 是中文连字符写法,在大部分正则引擎里可直接用来匹配中文)
2.2 量词与贪婪、懒惰匹配
有了字符和字符类,只能描述“一个字符”的形状,但文本常常是“一串字符”。这时候要用量词:
| 量词 | 含义 |
|---|---|
* |
前一个字符出现 0 次或多次 |
+ |
前一个字符出现 1 |
