开发者正则表达式速查表
· 12分钟阅读
正则表达式简介
正则表达式(regex)是每个开发者都应该掌握的强大模式匹配工具。它们提供了一种简洁、声明式的方式来搜索、验证和操作文本数据,而无需编写冗长的字符串操作代码。
无论您是在构建表单验证、解析日志文件、从API提取数据,还是清理数据集,正则表达式都能提供优雅的解决方案。单个正则表达式模式可以替代数十行条件逻辑,使您的代码更易于维护且更不容易出错。
JavaScript、Python、Java、PHP和Ruby等现代编程语言都内置了正则表达式支持。一旦学会了语法,您就可以在几乎任何开发环境中应用这些技能。
专业提示:正则表达式起初可能看起来很神秘,但它们遵循一致的模式。从简单的表达式开始,随着信心的增长逐渐增加复杂性。使用在线正则表达式测试工具进行实验并实时可视化匹配结果。
基本语法和元素
在处理复杂模式之前,理解正则表达式的基本构建块至关重要。这些核心元素构成了您将编写的每个正则表达式的基础。
字面字符
最简单的正则表达式模式完全按照字符出现的方式匹配字面字符。模式cat匹配文本中出现的字符串"cat"。
大多数字母数字字符都是字面的,但某些特殊字符(称为元字符)具有特殊含义,当您想要按字面匹配它们时,必须使用反斜杠进行转义。
基本元字符
| 模式 | 描述 | 示例 | 匹配 |
|---|---|---|---|
. |
匹配除换行符外的任何单个字符 | c.t |
"cat"、"cot"、"c9t" |
^ |
断言字符串开始位置 | ^Hello |
"Hello world"(仅在开头) |
$ |
断言字符串结束位置 | world$ |
"Hello world"(仅在结尾) |
* |
匹配0次或多次重复 | ab*c |
"ac"、"abc"、"abbc" |
+ |
匹配1次或多次重复 | ab+c |
"abc"、"abbc"(不匹配"ac") |
? |
匹配0次或1次出现 | colou?r |
"color"、"colour" |
| |
选择(OR运算符) | cat|dog |
"cat"或"dog" |
\ |
转义特殊字符 | \. |
字面句点字符 |
转义特殊字符
当您需要按字面匹配元字符时,在它们前面加上反斜杠。例如,要匹配字面句点,使用\.而不是.
需要转义的常见字符包括:. * + ? ^ $ { } [ ] ( ) | \
// 匹配字面问号
const pattern = /What\?/;
pattern.test("What?"); // true
// 匹配美元金额
const price = /\$\d+\.\d{2}/;
price.test("$19.99"); // true
字符类和量词
字符类允许您匹配特定集合中的任何字符,而量词控制模式应重复多少次。它们共同构成了灵活模式匹配的支柱。
预定义字符类
| 类 | 描述 | 等效 | 示例 |
|---|---|---|---|
\d |
任何数字 | [0-9] |
\d{3}匹配"123" |
\D |
任何非数字 | [^0-9] |
\D+匹配"abc" |
\w |
单词字符(字母数字+下划线) | [A-Za-z0-9_] |
\w+匹配"user_123" |
\W |
非单词字符 | [^A-Za-z0-9_] |
\W匹配"@"或" " |
\s |
空白字符(空格、制表符、换行符) | [ \t\n\r\f\v] |
\s+匹配" " |
\S |
非空白字符 | [^ \t\n\r\f\v] |
\S+匹配"hello" |
自定义字符集
方括号定义自定义字符集。模式[aeiou]匹配任何单个元音字母,而[0-9a-fA-F]匹配任何十六进制数字。
在方括号内使用插入符号来否定集合:[^0-9]匹配任何不是数字的字符。
// 匹配任何元音字母
const vowels = /[aeiou]/gi;
"Hello World".match(vowels); // ["e", "o", "o"]
// 仅匹配辅音字母
const consonants = /[^aeiou\s]/gi;
"Hello".match(consonants); // ["H", "l", "l"]
量词详解
量词指定前面的元素应匹配多少次。默认情况下它们是贪婪的,这意味着它们匹配尽可能多的文本。
{n}- 恰好n次:\d{4}恰好匹配4个数字{n,}- 至少n次:\d{3,}匹配3个或更多数字{n,m}- n到m次之间:\d{2,4}匹配2、3或4个数字*- 零次或多次(等同于{0,})+- 一次或多次(等同于{1,})?- 零次或一次(等同于{0,1})
快速提示:在任何量词后添加问号使其变为非贪婪(惰性)。例如,.*?匹配尽可能少的字符而不是尽可能多的字符。这在提取分隔符之间的内容时至关重要。
锚点和单词边界
锚点不匹配字符——它们匹配字符串中的位置。当您需要确保文本出现在特定位置时,它们对于精确的模式匹配至关重要。
位置锚点
插入符号^匹配字符串(或多行模式下的行)的开始,而美元符号$匹配结束。这些对于整个字符串必须匹配模式的验证非常宝贵。
// 验证整个字符串都是数字
const onlyDigits = /^\d+$/;
onlyDigits.test("12345"); // true
onlyDigits.test("123abc"); // false
// 匹配以"Error"开头的行
const errorLines = /^Error/gm;
const logs = "Info: Starting\nError: Failed\nError: Timeout";
logs.match(errorLines); // ["Error", "Error"]
单词边界
\b锚点匹配单词边界——单词字符和非单词字符之间的位置。它非常适合匹配整个单词而不会意外匹配较大单词的一部分。
\B锚点匹配不是单词边界的位置。
// 仅匹配完整单词"cat"
const wholeCat = /\bcat\b/;
wholeCat.test("cat"); // true
wholeCat.test("cats"); // false
wholeCat.test("concatenate"); // false
// 匹配单词内的"cat"
const partialCat = /\Bcat\B/;
partialCat.test("concatenate"); // true
partialCat.test("cat"); // false
单词边界对于搜索和替换操作特别有用,当您想避免部分匹配时。在构建语法高亮器或代码分析器时,它们也是必不可少的。
分组和捕获
正则表达式中的括号有多种用途:它们将模式的各部分组合在一起,捕获匹配的文本以供以后使用,并在模式本身内启用反向引用。
捕获组
括号创建存储匹配文本的编号捕获组。您可以在替换字符串中引用这些捕获,或以编程方式提取它们。
// 提取日期组件
const datePattern = /(\d{4})-(\d{2})-(\d{2})/;
const match = "2026-03-31".match(datePattern);
// match[0]: "2026-03-31"(完整匹配)
// match[1]: "2026"(年)
// match[2]: "03"(月)
// match[3]: "31"(日)
// 使用捕获重新格式化日期
const text = "Date: 2026-03-31";
const reformatted = text.replace(/(\d{4})-(\d{2})-(\d{2})/, "$2/$3/$1");
// 结果:"Date: 03/31/2026"
非捕获组
使用(?:...)对模式进行分组而不创建捕获。当您只需要分组用于选择或量词时,这可以提高性能并保持捕获编号清晰。
// 分组但不捕获
const protocol = /(?:https?|ftp):\/\//;
protocol.test("https://example.com"); // true
// 与捕获比较(不必要的开销)
const protocolCapture = /(https?|ftp):\/\//;
// 创建了一个我们不需要的额外捕获组
命名捕获组
现代正则表达式引擎支持使用(?<name>...)语法的命名捕获。这使您的模式自文档化且更易于维护。
// 命名捕获以提高清晰度
const emailPattern = /(?<user>[\w.]+)@(?<domain>[\w.]+)/;
const match = "[email protected]".match(emailPattern);
console.log(match.groups.user); // "john.doe"
console.log(match.groups.domain); // "example.com"
// 在替换中使用
const masked = "[email protected]".replace(
/(?<user>[\w.]+)@(?<domain>[\w.]+)/,
"***@$<domain>"
);
// 结果:"***@example.com"
反向引用
使用\1、\2等在同一模式内引用较早的捕获。这对于匹配重复或镜像模式非常强大。
// 匹配重复的单词
const repeated = /\b(\w+)\s+\1\b/;
repeated.test("hello hello"); // true
repeated.test("hello world"); // false
// 匹配HTML标签
const htmlTag = /<(\w+)>.*?<\/\1>/;
htmlTag.test("<div>content</div>"); // true
htmlTag.test("<div>content</span>"); // false
正则表达式标志和修饰符
标志修改正则表达式引擎解释模式的方式。在大多数语言中,它们添加在结束分隔符之后(例如,JavaScript中的/pattern/flags)。
常见标志
- g(全局) - 查找所有匹配而不是在第一次匹配后停止
- i(不区分大小写) - 匹配字母时忽略大小写
- m(多行) - 使
^和$匹配行边界而不是字符串边界 - s(dotall) - 使
.匹配换行符 - u(unicode) - 启用完整的Unicode支持
- y(粘性) - 仅从lastIndex位置开始匹配
// 不区分大小写搜索
const pattern = /hello/i;
pattern.test("HELLO"); // true
pattern.test("Hello"); // true
// 全局标志用于多次匹配
const digits = /\d+/g;
"Phone: 555-1234, Fax: 555-5678".match(digits);
// ["555", "1234", "555", "5678"]
// 多行模式
const headers = /^#.+$/gm;
const markdown = "# Title\nContent\n## Subtitle";
markdown.match(headers); // ["# Title", "## Subtitle"]
专业提示:全局标志会改变exec()和test()等方法的行为方式——它们在调用之间维护状态。如果您得到意外结果,请检查是否需要全局标志或它是否导致有状态匹配问题。
常见模式及其应用
让我们探索经过实战检验的常见开发任务正则表达式模式。这些模式经过实际使用的完善,可以处理您最初可能不会考虑的边缘情况。
电子邮件验证
由于RFC规范,电子邮件验证非常复杂,但这个实用模式可以处理99%的真实世界电子邮件地址:
const emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
// 有效的电子邮件
emailPattern.test("[email protected]"); // true
emailPattern.test("[email protected]"); // true
// 无效的电子邮件
emailPattern.test("invalid@"); // false
emailPattern.test("@example.com"); // false
emailPattern.test("[email protected]"); // false
对于生产应用程序,请考虑使用专门的电子邮件验证库来处理国际化域名和所有RFC边缘情况。您还可以使用我们的电子邮件验证工具交互式测试电子邮件模式。
URL匹配
使用这个全面的模式从文本中匹配和提取URL:
const urlPattern