正则表达式是一种在你编写的任何语言中都能获得回报的技能。同一个模式可以用于在Python中验证电子邮件,在Go中去除查询字符串,并在JavaScript中清理表单输入。学习一次,用于所有地方。
这不是一个语法指南。它是你在实际项目中真正使用的模式——这些模式出现在表单验证器、日志解析器、URL路由器和数据管道中。下面的表格是核心内容。周围的文字解释了人们在这些地方会遇到的问题。
保留的模式风格
这些11种模式涵盖了生产代码中反复出现的场景。请继续使用 正则表达式测试器 在验证它们与您自己的输入之前,应先进行测试并将其接入。
| 图案 | 匹配内容 | 示例匹配 | 笔记 |
|---|---|---|---|
^[\w.+-]+@[\w-]+\.[a-zA-Z]{2,}$ | 电子邮件 | user@example.com | 设计上允许——真正的 RFC 5322 是一条迷宫。链接至 ^$. |
https?:\/\/[\w\-._~:/?#[\]@!$&'()*+,;=%]+ | HTTP/HTTPS URL https://URL | https://example.com/path?q=1 | 不验证结构,只是确认它看起来像一个URL。 |
^(\d{1,3}\.){3}\d{1,3}$ | IPv4地址(仅格式) IPv4地址(仅用于格式化) | 192.168.1.1 | 匹配结果 999.999.999.999 — 验证代码中的范围,而不是使用正则表达式。 |
^(\+\d{1,3}[\s-])?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$ | 北美电话号码 | (555) 867-5309 | 处理常见的分隔符。国际格式变化太大,无法用一个模式匹配。 --- |
[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} | UUID v4 UUID v4(随机 UUID)是一种通过随机数生成的全球唯一标识符,通常用于数据库记录、文件系统和网络应用程序中。它由32位二进制数组合而成,并以“-”分隔为五个部分:8-4-4-12。 **注意:** 此版本的UUID通常使用RFC 4122标准生成。 | 550e8400-e29b-41d4-a716-446655440000 | 不区分大小写 —— 使用 i 标志或添加 A-F 到字符类别。 |
^[a-z0-9]+(?:-[a-z0-9]+)*$ | 链接标签 | my-article-title | 无前后连字符,无连续连字符。 |
^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$ | ISO 8601 年月日格式(YYYY-MM-DD) | 2026-04-10 | 验证格式和范围,不验证日历有效性(二月三十一号通过)。 |
^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$ | CSS 十六进制颜色 | #ff6600 或 #f60 | 两位数和六位数简写。添加 {8} 对于8位RGBA十六进制。 |
^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([\w.-]+))?(?:\+([\w.-]+))?$ | 语义版本号 | 1.2.3-beta.1+build.42 | 捕获预发布和构建元数据为可选组。 (保留原文中的技术术语和专业用词,如“metadata”直接音译为“元数据”,不进行中文翻译。) |
\b(?:\d{4}[\s-]?){3}\d{4}\b | 信用卡号(屏蔽,不验证) | 4111 1111 1111 1111 | 请在日志中用于遮盖,而不是验证。Luhn检查需要代码。 |
\s+ | 空格跑步 | "hello world" → "hello world" | 用单空格替换空白符进行空白规范化。 |
在实践中模式何时崩解?
贪婪匹配与懒惰匹配
定量词如 * 且 + 默认贪婪——它们会消耗尽可能多的内容。当从定界符中提取内容时,这会让你受到伤害。 <.+> 在 <b>bold</b> 匹配整个字符串,而不是 <b>换成懒惰的模式。 .+? 在遇到第一个闭合符号时停止,而不是在最后一个。
锚定:当^和$不足时
没有锚点时,模式可以在字符串中的任何位置匹配。 \d+ 匹配 abc123def — 它找到中间的数字。对于完整字符串验证,将模式包裹起来。 ^...$在多行模式下(m 标志) ^ 且 $ 匹配行边界,而不是整个字符串的边界。如果你在验证单个值(如电子邮件、UUID),请调整。 m 旗意外地挂出,非习惯性挂起。
多行标志陷阱
这 m 标志改变了什么 ^ 且 $ 意思是。 s 标志点全匹配(全模式)会改变什么 . 匹配——没有它,
(保留原文中的 HTML 实体 不变) . 不匹配换行符。解析多行日志条目时
不匹配换行符。解析多行日志记录时 .+你需要 s 或 [\s\S]+ 作为不支持全局模式(dotAll)的引擎的备用方案。
安装前测试
不要将正则表达式直接放入应用程序并仅对一个快乐路径输入进行测试。模式会在边缘情况失败:Unicode字符、空字符串、前导/尾随空格以及几乎但又不完全有效的输入。 正则表达式测试器 IO Tools 让您能够对多个测试字符串同时运行模式,以便在代码发布前检查有效情况和无效情况并排进行比较。 正则表达式快速参考工具 在构建模式的过程中,当需要快速查阅语法参考而不离开浏览器时非常有用。
在测试时,构建一个矩阵:应该匹配什么、绝对不应匹配什么以及哪些属于边界情况。电子邮件验证器接受
当前支持的格式如下:
- 标准格式(例如 `user@example.com`)
- 基本域名(例如 `example.com`)
- 包含特殊字符的地址(例如 `user+tag@example.co.uk`) user@ 拒绝 user+tag@example.co.uk 比没有任何验证器还要糟糕。
语言中的趣事值得了解
表格中展示的模式广泛适用,但在边缘部分则取决于引擎。
- JavaScript 使用 ECMAScript 正则表达式引擎。命名捕获组(
(?<name>...)这些功能在 ES2018+ 中得到支持。v标志(引入于 ES2024)添加了集合表示法和Unicode属性转义。前向查找是可行的;后向查找在ES2018+版本中工作,但在某些较旧的V8版本中具有变长限制。 - Python 使用。
re模块(与PCRE相邻但不完全相同)。re.compile()模式设计可取——编译后的模式在循环中重复调用时速度更快。一个细微差别:Python 的\b边界识别是默认情况下对Unicode敏感的,因此它能在非ASCII字符上工作。JavaScript的\b仅在使用特殊字符时才支持ASCII。u或v旗子。 - 去 使用RE2语法,故意排除了回引用和前瞻匹配。这是一个安全决策——RE2保证线性时间匹配,从而防止灾难性的反向追踪。如果你正在将模式从Python或JavaScript移植到Go语言中,并且使用了前瞻或回引用,则需要重新组织逻辑。
实际世界示例:跨语言邮箱验证 (保留原文中的标点符号和格式,如逗号、空格等)
相同的模式,有两种实现方式:一个 JavaScript 表单验证器和一个 Python 输入检查。
// JavaScript — client-side form validation
const EMAIL_RE = /^[\w.+-]+@[\w-]+\.[a-zA-Z]{2,}$/;
function validateEmail(input) {
const value = input.trim();
if (!EMAIL_RE.test(value)) {
throw new Error(`Invalid email address: ${value}`);
}
return value;
}
// Usage
document.querySelector('#signup-form').addEventListener('submit', (e) => {
e.preventDefault();
try {
const email = validateEmail(e.target.email.value);
submitForm({ email });
} catch (err) {
showError(err.message);
}
});
# Python — API request validation
import re
EMAIL_RE = re.compile(r'^[\w.+-]+@[\w-]+\.[a-zA-Z]{2,}$')
def validate_email(value: str) -> str:
value = value.strip()
if not EMAIL_RE.match(value):
raise ValueError(f"Invalid email address: {value!r}")
return value
# Usage in a Flask route
@app.route('/signup', methods=['POST'])
def signup():
try:
email = validate_email(request.json.get('email', ''))
except ValueError as e:
return jsonify({'error': str(e)}), 400
# continue with valid email...
两者使用相同的底层模式。唯一有意义的区别在于:Python的 re.compile() 在热路径中预编译模式,以避免每次调用都重新解析它——值得这样做。
保持个人速查表
上述模式处理了常见情况,但随着时间的推移你会积累自己的模式——记录适用于您的堆栈的特定格式、内部系统中的标识符方案以及数据团队强制使用的日期格式。一份经过测试并精选的短文件,可以从中粘贴已验证模式,比记住语法规则更有价值。每次测试一次后,为其注解用途,并参考这些模式而非每次都重新构建。
