正则表达式:实用指南与示例

· 12分钟阅读

正则表达式(regex)是开发者工具箱中最强大的工具之一,但它们经常被误解或完全避免使用。无论你是在验证用户输入、解析日志文件,还是转换文本数据,正则表达式都提供了一种简洁高效的方式来匹配字符串中的模式。

这份综合指南将带你从正则表达式基础到高级技巧,提供可以立即在项目中使用的实用示例。最后,你不仅会理解正则表达式如何工作,还会明白何时以及为什么使用它。

目录

什么是正则表达式以及为什么你应该关心?

正则表达式是定义搜索模式的字符序列。可以把它看作是专门为文本中的模式匹配设计的迷你语言。正则表达式不是搜索精确字符串,而是让你描述诸如"任何电子邮件地址"或"此格式的所有电话号码"之类的模式。

正则表达式几乎在每种编程语言和许多命令行工具中都受支持。一旦你学会了语法,就可以在任何地方应用它——从JavaScript和Python到grep和sed。

常见用例包括:

专业提示: 虽然正则表达式很强大,但它并不总是正确的工具。对于像HTML或JSON这样的复杂解析任务,请使用专用解析器。正则表达式最适合定义明确、相对简单的模式。

正则表达式基础:构建块

每个正则表达式模式都是由基本构建块构成的。在转向更复杂的模式之前,理解这些核心元素至关重要。

字面字符

最简单的正则表达式就是字面文本。模式cat匹配文本中的精确字符串"cat"。大多数字母数字字符直接匹配它们自己。

元字符

某些字符在正则表达式中具有特殊含义。这些被称为元字符,包括:. ^ $ * + ? { } [ ] \ | ( )

要按字面意思匹配这些字符,你需要用反斜杠转义它们。例如,\.匹配字面句点。

点通配符

.是最基本的通配符——它匹配除换行符外的任何单个字符。模式a.c匹配"abc"、"a1c"、"a-c",但不匹配"ac"(中间没有字符)或"a\nc"(换行符)。

模式 匹配 示例
. 任何字符(除换行符外) a.c匹配abc、a1c、a-c
\d 任何数字[0-9] \d{3}匹配123、456
\w 单词字符[a-zA-Z0-9_] \w+匹配hello、user_1
\s 空白字符(空格、制表符、换行符) \s+匹配空格、制表符
\D 非数字 \D+匹配abc、xyz
\W 非单词字符 \W+匹配!@#、空格
\S 非空白字符 \S+匹配任何可见文本

注意大写版本(\D\W\S)是其小写对应项的反义。这是正则表达式语法中的常见模式。

量词:控制重复

量词指定模式应重复多少次。它们放在你想要重复的元素之后,是创建灵活模式的基础。

基本量词

量词 含义 示例
* 0次或多次 ab*c匹配ac、abc、abbc、abbbc
+ 1次或多次 ab+c匹配abc、abbc(不匹配ac)
? 0次或1次(可选) colou?r匹配color、colour
{n} 恰好n次 \d{4}匹配2026、1999
{n,} n次或更多次 \d{3,}匹配123、1234、12345
{n,m} n到m次之间 \d{2,4}匹配12、123、1234

贪婪匹配与懒惰匹配

默认情况下,量词是贪婪的——它们尽可能多地匹配文本。这在匹配HTML标签等模式时可能导致意外结果。

// 贪婪匹配
const text = "<div>Hello</div><div>World</div>";
const greedy = /<.*>/;
// 匹配:"<div>Hello</div><div>World</div>"(整个字符串!)

// 懒惰匹配
const lazy = /<.*?>/;
// 匹配:"<div>"(在第一个闭合括号处停止)

在量词后添加?使其变为懒惰(非贪婪)。懒惰量词在满足模式的同时尽可能少地匹配文本。

快速提示: 在匹配分隔符(引号、括号、标签)之间的内容时,懒惰量词通常是你想要的。使用.*?而不是.*以避免匹配过多。

字符类和快捷方式

字符类让你匹配特定集合中的任何字符。它们使用方括号定义,对于创建灵活的模式非常有用。

基本字符类

// 匹配任何元音
/[aeiou]/

// 匹配任何数字
/[0-9]/

// 匹配任何小写字母
/[a-z]/

// 匹配任何字母(不区分大小写)
/[a-zA-Z]/

// 匹配字母数字字符
/[a-zA-Z0-9]/

否定字符类

在字符类开头使用^来否定它——匹配除了列出的字符之外的任何字符。

// 匹配任何非数字
/[^0-9]/

// 匹配任何非元音
/[^aeiou]/

// 匹配除空格或制表符外的任何字符
/[^ \t]/

字符类中的特殊字符

大多数元字符在字符类内部失去其特殊含义。你可以包含.*+?而无需转义它们。但是,在某些位置你仍然需要转义]\^-

// 匹配句点或逗号
/[.,]/

// 匹配连字符(转义或放在开头/结尾)
/[-a-z]/或/[a-z-]/

// 匹配闭合括号(必须转义)
/[\]]/

分组和捕获

分组有两个主要目的:它们让你将量词应用于多个字符,并且它们捕获匹配的文本以供以后使用。

捕获组

括号创建记住匹配文本的捕获组。这对于从字符串中提取数据至关重要。

// 提取日期组件
const datePattern = /(\d{4})-(\d{2})-(\d{2})/;
const match = "2026-03-29".match(datePattern);

// match[0]:"2026-03-29"(完整匹配)
// match[1]:"2026"(第一组)
// match[2]:"03"(第二组)
// match[3]:"29"(第三组)

命名捕获组

命名组使你的正则表达式更易读,代码更易维护。你不是通过数字引用组,而是给它们描述性的名称。

// 命名组语法:(?<name>pattern)
const datePattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = "2026-03-29".match(datePattern);

// 通过名称访问
console.log(match.groups.year);  // "2026"
console.log(match.groups.month); // "03"
console.log(match.groups.day);   // "29"

非捕获组

有时你需要分组用于量词或选择,但不想捕获文本。非捕获组使用(?:...)语法。

// 捕获协议而不创建组
/(?:https?|ftp):\/\/([a-z.]+)/

// 这只创建一个捕获组(域名)
// 协议组(?:https?|ftp)不捕获

非捕获组比捕获组更快,使用更少的内存。当你不需要捕获的文本时使用它们。

反向引用

反向引用让你匹配先前组捕获的相同文本。这对于查找重复单词或匹配成对分隔符很有用。

// 查找重复单词
/\b(\w+)\s+\1\b/
// 匹配"the the"或"hello hello"

// 匹配成对引号
/(['"])(.*?)\1/
// 匹配"hello"或'world'但不匹配"mixed'

选择

管道|运算符创建选择——匹配一个模式或另一个。它就像逻辑OR。

// 匹配cat、dog或bird
/cat|dog|bird/

// 匹配常见文件扩展名
/\.(jpg|jpeg|png|gif|webp)$/i

// 匹配Mr.、Mrs.、Ms.或Dr.
/(?:Mr|Mrs|Ms|Dr)\./

锚点和边界

锚点不匹配字符——它们匹配字符串中的位置。它们对于确保模式出现在特定位置至关重要。

字符串锚点

// 必须以"Hello"开头
/^Hello/

// 必须以"world"结尾
/world$/

// 整个字符串必须恰好是5位数字
/^\d{5}$/

单词边界

\b锚点匹配单词边界——单词字符和非单词字符之间的位置。这对于匹配整个单词至关重要。

// 匹配"cat"作为整个单词
/\bcat\b/
// 匹配:"cat"、"the cat sat"
// 不匹配:"category"、"scat"

// 匹配以"pre"开头的单词
/\bpre\w+/
// 匹配:"preview"、"prepare"、"prefix"

反义\B匹配非单词边界——两侧都是单词字符或两侧都是非单词字符的位置。

专业提示: 在搜索整个单词时始终使用单词边界。没有它们,搜索"cat"也会匹配"category"和"concatenate"。模式\bcat\b确保你只匹配完整的单词。

实际使用的常见模式

这里是经过实战检验的常见验证和提取任务的正则表达式模式。这些模式在简单性和实用准确性之间取得平衡。

模式类型 正则表达式 注释
电子邮件(简单) ^[\w.-]+@[\w.-]+\.[a-zA-Z]{2,}$ 适合基本验证
电子邮件(符合RFC) ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ 更严格,广泛接受
URL ^https?:\/\/[\w.-]+(?:\.[a-zA-Z]{2,})(?:\/\S*)?$ 基本HTTP/HTTPS URL
IPv4地址 ^(?:\d{1,3}\.){3}\d{1,3}$ 仅格式,不验证范围
IPv4(严格) ^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ 验证0-255范围
日期(YYYY-MM-DD) ^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$ ISO 8601格式
时间(24小时) ^(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?$ HH:MM或HH:MM:SS
电话(美国) ^\+?1?[-.\s]?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$ 灵活格式
十六进制颜色 ^#(?:[0-9a-fA-F]{3}){1,2}$ 3位或6位十六进制代码
信用卡 ^\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}$ 仅格式,使用Luhn验证
用户名 ^[a-zA-Z0-9_-]{3,16}$ 3-16个字符,字母数字加_和-
Slug ^[a-z0-9]+(?:-[a-z0-9]+)*$ URL友好的小写带连字符

密码验证

密码验证需要同时检查多个条件。前瞻断言使这成为可能,而无需复杂的逻辑。

// 强密码:8个以上字符,大写、小写、数字、特殊字符
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/

// 分解说明:
// (?=.*[a-z])     - 至少一个小写字母
// (?=.*[A-Z])     -