正则表达式(regex)是一种可复用的模式模板,用于匹配文本中特定的字符序列 - 你可以把它理解成一个超强的"查找"工具,几乎适用于所有主流编程语言。无论是验证邮箱地址、从表单中提取手机号,还是解析日志文件,掌握几个常用的正则表达式就能搞定 90% 的需求。本文整理了最实用的正则模式,逐一解释每个部分的作用,并教你如何灵活改写。
正则语法速查
在介绍各类模式之前,先来看一张常用语法元素速查表。即使你之前用过正则表达式,把这些基础元素放在一起查阅也非常方便。
| 元字符 | 含义 | 匹配示例 |
|---|---|---|
.
|
匹配除换行符以外的任意字符 |
a.c
可匹配
abc
、
a1c
|
\d
|
任意数字(0-9) |
\d\d
可匹配
42
|
\w
|
单词字符(字母、数字、下划线) |
\w+
可匹配
hello_world
|
\s
|
空白字符(空格、制表符、换行符) |
\s+
可匹配多个连续空格
|
^
/
$
|
字符串的开头 / 结尾 |
^\d+$
仅匹配
123
|
{n,m}
|
重复 n 到 m 次 |
\d{2,4}
可匹配
12
到
1234
|
[abc]
|
字符类 - 匹配 a、b、c 中的任意一个 |
[aeiou]
可匹配任意元音字母
|
(?:...)
|
非捕获分组 | 分组但不保存反向引用 |
(?=...)
|
正向前瞻 | 断言后续内容,但不消耗字符 |
MDN Web Docs 正则表达式指南 是学习 JavaScript 正则语法最好的参考资料,下面大多数模式也可以直接用于 Python、PHP、Java 和 Ruby,只需根据各语言的标志位稍作调整即可。
邮箱验证
邮箱验证是正则表达式最经典的使用场景,也是很多开发者容易写过头的地方。
RFC 5322 规范
理论上允许
"very unusual"@example.com
这样的地址格式,但几乎没有正则能完整覆盖。对于 99% 的实际表单验证场景,用下面这个务实的模式就够了:
^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$
各部分说明:
-
[a-zA-Z0-9._%+\-]+- 本地部分(@ 之前);允许点号、加号、连字符、下划线 -
@- 字面量 @ 符号 -
[a-zA-Z0-9.\-]+- 域名,包含子域名 -
\.[a-zA-Z]{2,}- 至少 2 个字符的顶级域名(如 .io、.com、.museum)
URL 与网址匹配
URL 模式匹配的应用场景很广,从从纯文本中提取链接,到验证用户填写的网址字段,都能用到。
https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_+.~#?&\/=]*)
-
https?- 同时匹配http和https -
(?:www\.)?- 可选的 www 前缀 -
[-a-zA-Z0-9@:%._+~#=]{1,256}- 主机名字符,最多 256 个字符 -
\.[a-zA-Z0-9()]{1,6}- 顶级域名 -
\b(?:[-a-zA-Z0-9()@:%_+.~#?&\/=]*)- 可选的路径、查询字符串和片段标识符
如果只需要验证而不需要提取,可以在模式前后加上
^
和
$
锚点。
手机号与电话号码
电话号码的格式因国家和用户习惯差异极大,处理起来比较麻烦。下面两个模式可以覆盖大多数常见场景:
美国/加拿大(NANP)格式
^(\+1[-.\s]?)?(\(?\d{3}\)?[-.\s]?)?\d{3}[-.\s]?\d{4}$
可匹配:
555-867-5309
、
(555) 867 5309
、
+1.555.867.5309
、
5558675309
国际格式(E.164)
^\+[1-9]\d{6,14}$
E.164 是大多数电话 API(如 Twilio、AWS SNS)所使用的格式,以
+
加国家代码开头,不含空格或标点符号。
日期与时间
日期模式匹配在日志解析、表单验证和数据管道中非常常见。具体使用哪种格式,取决于你的数据来源。
ISO 8601 格式(YYYY-MM-DD)
^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
美式格式(MM/DD/YYYY)
^(0[1-9]|1[0-2])\/(0[1-9]|[12]\d|3[01])\/\d{4}$
24 小时制时间(HH:MM 或 HH:MM:SS)
^([01]\d|2[0-3]):([0-5]\d)(?::([0-5]\d))?$
注意,这些模式只验证格式,不验证日历逻辑。例如
2024-02-31
(2月31日并不存在)也会被接受。如需严格验证日期合法性,请在正则检查之后再用语言内置的日期库进行解析。
密码强度验证
密码规则通常要求包含多种字符类型并满足最低长度。使用前瞻断言可以将这些规则写在一个模式里,无需拆分成多次检查。
最少 8 位,包含至少一个大写字母、一个小写字母、一个数字
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$
强密码:8 位以上,包含大写字母、小写字母、数字和特殊字符
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]).{8,}$
每个
(?=.*[...])
都是一个前瞻断言,用于扫描整个字符串,确保至少包含一个符合条件的字符。最后的
.{8,}
用于限制最低长度。你可以将
{8,}
替换为
{12,}
来要求最少 12 位,这也符合
NIST SP 800-63B 密码指南
的建议。
IP 地址匹配
IPv4
^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$
该模式通过明确匹配每个八位组(octet)的 0-255 范围,能正确拒绝
999.0.0.1
这类无效值。
IPv6(简化版)
^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$
该模式处理完整的 8 组格式。对于压缩表示法(例如用
::1
表示回环地址),正则会变得相当复杂,此时使用网络库来解析比正则更可靠。
HTML 与标记语言
在这个场景下,有几个针对性的正则模式确实很实用。"不要用正则解析 HTML"这条原则对完整文档仍然成立 - 完整的 HTML 文档请使用 BeautifulSoup 或 DOMParser 这类专业 DOM 解析器。但对于特定的、范围明确的任务,正则完全可以胜任。
去除所有 HTML 标签
<[^>]*>
提取特定标签的内容(例如 <title>)
([^<]*)<\/title>
第 1 个捕获分组包含标题文本内容。
匹配 HTML 十六进制颜色值
#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})\b
同时匹配 3 位简写形式(
#fff
)和 6 位完整形式(
#ffffff
)。
常用工具型正则
以下这些模式在各类项目中频繁出现,非常值得收藏。
Slug(URL 友好字符串)
^[a-z0-9]+(?:-[a-z0-9]+)*$
可匹配
my-blog-post-2024
这样的字符串。不含大写字母,不以连字符开头或结尾,不包含连续连字符。
信用卡号(基本格式,不含空格)
^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|6(?:011|5[0-9]{2})[0-9]{12})$
-
以
4开头 - Visa(13 或 16 位) -
以
51-55开头 - Mastercard(16 位) -
以
34或37开头 - Amex(15 位) -
以
6011或65开头 - Discover(16 位)
空白字符规范化(合并多余空格)
\s{2,}
将匹配到的内容替换为单个空格,用于清理用户输入或爬取文本中的多余空白。
仅匹配数字
^\d+$
仅匹配字母和数字
^[a-zA-Z0-9]+$
匹配包含某个单词的行(配合标志位实现大小写不敏感)
^.*\bword\b.*$
单词边界
\b
可以防止在
password
这类单词内部误匹配
word
。
提取版本号(semver 格式)
\bv?(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9.]+))?(?:\+([a-zA-Z0-9.]+))?\b
可从
v2.14.0-beta.1+build.42
这样的字符串中捕获主版本号、次版本号、修订号、预发布标签和构建元数据。
标志位与实用技巧
正则表达式的行为会因所使用的标志位不同而有所差异。以下是最常用的几个:
| 标志位 | JS | Python | 效果 |
|---|---|---|---|
| 大小写不敏感 |
i
|
re.IGNORECASE
|
大写和小写字母视为相同 |
| 全局匹配(查找所有) |
g
|
re.findall()
|
返回所有匹配结果,而不仅是第一个 |
| 多行模式 |
m
|
re.MULTILINE
|
^
和
$
匹配每行的行首/行尾,而不是整个字符串的开头/结尾
|
| 点号全匹配(dotall) |
s
|
re.DOTALL
|
.
也能匹配换行符
|
几个能帮你节省大量调试时间的好习惯:
- 始终用边界情况测试 - 空字符串、最大长度、Unicode 字符,以及那些"看起来合法但其实不合法"的输入。
-
不需要捕获内容时,使用非捕获分组
(?:...)- 比捕获分组更快,代码也更清晰。 -
验证模式一定要加锚点
,使用
^和$,防止无效字符串中的合法子串"蒙混过关"。 -
警惕灾难性回溯
- 像
(a+)+这样的嵌套量词,在精心构造的输入下可能导致正则引擎卡死。量词应尽量保持简单和具体。 - 编写正则时使用在线调试工具 。 regex101.com 提供实时匹配分析,能解释每个语法元素的含义,并支持在 PCRE、JavaScript、Python 等多种引擎之间切换。
告别猜测,轻松测试和验证正则表达式
有了合适的工具,编写可靠的正则验证模式会快得多。探索我们的免费开发者工具,使用正则表达式对文本进行清洗、检查和转换。
立即体验免费工具 →
贪婪量词(如
.*
)会尽可能多地匹配字符,然后再回溯。懒惰量词(如
.*?
)则尽可能少地匹配字符。例如,对于字符串
bold
,模式
<.*>
会匹配整个字符串,而
<.*?>
只会匹配
。在提取分隔符之间的内容时,使用懒惰量词更合适。
大体一致,但存在一些差异。Python 的
re
模块使用 PCRE 风格语法,支持
(?P
形式的命名分组。JavaScript 的标志位语法略有不同,旧版引擎(ES2018 之前)不支持后向断言。如果需要跨语言兼容,建议只使用通用子集:字符类、量词、锚点和基本分组。
用正则做格式验证在生产环境中完全没问题,几乎所有 Web 框架都在这样做。真正的风险在于写得不好的模式可能引发 ReDoS(正则拒绝服务)攻击,即通过触发灾难性回溯来耗尽资源。避免使用嵌套量词,让模式尽量具体,并在正则运行之前就限制合理的输入长度。
在大多数常见引擎中,对于 ASCII 输入两者是等价的。区别在于 Unicode 场景下:在某些引擎(如开启 Unicode 模式的 Python 3)中,
\d
会匹配其他文字系统的数字,例如阿拉伯-印度数字。如果你明确只想匹配 ASCII 数字 0-9,使用
[0-9]
更严谨。对于大多数 Web 表单验证来说,这个区别通常不影响实际使用。
你需要两样东西:dotall 标志位(让
.
也能匹配换行符),以及可能还需要多行标志位(让
^
和
$
锚定到每一行,而不是整个字符串的首尾)。在 JavaScript 中使用
/pattern/ms
;在 Python 中组合使用
re.DOTALL | re.MULTILINE
。如果不开启 dotall,
.
会在换行处停止,模式就无法跨行匹配。