正则表达式速查表
快速查阅正则表达式的语法和常用模式。
基础语法
字符匹配
| 模式 | 说明 | 示例 |
|---|---|---|
abc | 精确匹配 | /abc/ 匹配 "abc" |
. | 任意字符(除换行) | /a.c/ 匹配 "abc", "a1c" |
\ | 转义字符 | /a\*b/ 匹配 "a*b" |
| | 或操作 | /a|b/ 匹配 "a" 或 "b" |
字符类
| 模式 | 说明 | 等价于 |
|---|---|---|
[abc] | a、b 或 c 中的任意一个 | - |
[^abc] | 除 a、b、c 外的任意字符 | - |
[a-z] | a 到 z 的任意小写字母 | - |
[A-Z] | A 到 Z 的任意大写字母 | - |
[0-9] | 0 到 9 的任意数字 | - |
[a-zA-Z] | 任意字母 | - |
[a-zA-Z0-9] | 任意字母或数字 | - |
预定义字符类
| 模式 | 说明 | 等价于 |
|---|---|---|
\d | 数字 | [0-9] |
\D | 非数字 | [^0-9] |
\w | 单词字符 | [a-zA-Z0-9_] |
\W | 非单词字符 | [^a-zA-Z0-9_] |
\s | 空白字符 | [ \t\n\r\f\v] |
\S | 非空白字符 | [^ \t\n\r\f\v] |
量词
| 模式 | 说明 | 示例 |
|---|---|---|
* | 零次或多次 | /a*/ 匹配 "", "a", "aaa" |
+ | 一次或多次 | /a+/ 匹配 "a", "aaa" |
? | 零次或一次 | /a?/ 匹配 "", "a" |
{n} | 恰好 n 次 | /a{3}/ 匹配 "aaa" |
{n,} | 至少 n 次 | /a{2,}/ 匹配 "aa", "aaa" |
{n,m} | n 到 m 次 | /a{2,4}/ 匹配 "aa", "aaa", "aaaa" |
*? | 非贪婪零次或多次 | 匹配尽可能少的字符 |
+? | 非贪婪一次或多次 | 匹配尽可能少的字符 |
?? | 非贪婪零次或一次 | 匹配尽可能少的字符 |
位置锚点
| 模式 | 说明 | 示例 |
|---|---|---|
^ | 字符串开头 | /^abc/ 匹配以 abc 开头 |
$ | 字符串结尾 | /abc$/ 匹配以 abc 结尾 |
\b | 单词边界 | /\bword\b/ 匹配完整单词 |
\B | 非单词边界 | /\Bword\B/ 匹配单词内部 |
分组与捕获
| 模式 | 说明 | 示例 |
|---|---|---|
(abc) | 捕获分组 | /(\d+)-(\d+)/ |
(?:abc) | 非捕获分组 | /(?:\d{4})-(\d{2})/ |
(?<name>abc) | 命名分组 | /(?<year>\d{4})/ |
\1, \2 | 反向引用 | /(")[^"]*\1/ |
\k<name> | 命名反向引用 | /(?<q>["'])[^\k<q>]*\k<q>/ |
零宽断言
| 模式 | 说明 | 示例 |
|---|---|---|
(?=abc) | 正向先行断言 | /\d(?=px)/ 匹配后面是 px 的数字 |
(?!abc) | 负向先行断言 | /\d(?!px)/ 匹配后面不是 px 的数字 |
(?<=abc) | 正向后行断言 | /(?<=\$)\d+/ 匹配前面是 $ 的数字 |
(?<!abc) | 负向后行断言 | /(?<!\$)\d+/ 匹配前面不是 $ 的数字 |
标志(修饰符)
| 标志 | 说明 | JavaScript | Python |
|---|---|---|---|
i | 忽略大小写 | /abc/i | re.I |
g | 全局匹配 | /abc/g | - |
m | 多行模式 | /abc/m | re.M |
s | dotAll 模式 | /abc/s | re.S |
u | Unicode 模式 | /abc/u | 默认 |
y | 粘性匹配 | /abc/y | - |
常用正则表达式模式
验证类
// 邮箱(简化版)
/^[\w.-]+@[\w.-]+\.\w{2,}$/
// 邮箱(完整版)
/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
// 中国手机号
/^1[3-9]\d{9}$/
// 固话号码(带区号)
/^0\d{2,3}-?\d{7,8}$/
// 身份证号(中国大陆)
/^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/
// 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]?)$/
// IPv6 地址(简化版)
/^([\da-fA-F]{1,4}:){7}[\da-fA-F]{1,4}$/
// URL
/^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/
// 日期(YYYY-MM-DD)
/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/
// 时间(HH:MM:SS)
/^([01]\d|2[0-3]):[0-5]\d:[0-5]\d$/
// 密码(至少8位,包含大小写字母和数字)
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/
// 密码(至少8位,包含大小写字母、数字和特殊字符)
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/
// 中文姓名(2-4个汉字)
/^[\u4e00-\u9fa5]{2,4}$/
// 邮政编码
/^\d{6}$/
提取类
// 提取 HTML 标签
/<(\w+)[^>]*>([^<]*)<\/\1>/g
// 提取 URL
/https?:\/\/[^\s]+/g
// 提取邮箱
/[\w.-]+@[\w.-]+\.\w{2,}/g
// 提取手机号
/1[3-9]\d{9}/g
// 提取中文
/[\u4e00-\u9fa5]+/g
// 提取 Markdown 链接
/\[([^\]]+)\]\(([^)]+)\)/g
// 提取图片地址
/<img[^>]+src=["']([^"']+)["'][^>]*>/gi
// 提取视频地址
/<video[^>]+src=["']([^"']+)["'][^>]*>/gi
替换类
// 去除所有 HTML 标签
str.replace(/<[^>]+>/g, "")
// 去除多余空白
str.replace(/\s+/g, " ")
// 去除行首行尾空白
str.replace(/^\s+|\s+$/g, "")
// 或使用 trim()
// 驽峰命名转下划线
"helloWorld".replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase()
// 结果: "hello_world"
// 下划线转驼峰命名
"hello_world".replace(/_([a-z])/g, (_, char) => char.toUpperCase())
// 结果: "helloWorld"
// 手机号码脱敏
"13812345678".replace(/(\d{3})\d{4}(\d{4})/, "$1****$2")
// 结果: "138****5678"
// 身份证号脱敏
"110101199001011234".replace(/(\d{6})\d{8}(\d{4})/, "$1********$2")
// 结果: "110101********1234"
// 日期格式转换(YYYY-MM-DD -> DD/MM/YYYY)
"2024-03-15".replace(/(\d{4})-(\d{2})-(\d{2})/, "$3/$2/$1")
// 结果: "15/03/2024"
各语言正则表达式用法
JavaScript
// 创建正则
const regex = /pattern/flags;
const regex = new RegExp("pattern", "flags");
// 测试
regex.test(string); // 返回 true/false
// 匹配
string.match(regex); // 返回数组或 null
string.matchAll(regex); // 返回迭代器
regex.exec(string); // 返回数组或 null
// 查找
string.search(regex); // 返回索引或 -1
// 替换
string.replace(regex, replacement);
string.replaceAll(regex, replacement);
// 分割
string.split(regex);
// 常甦标志
// i - 忽略大小写
// g - 全局匹配
// m - 多行模式
// s - dotAll 模式
// u - Unicode 模式
// y - 粘性匹配
Python
import re
# 创建模式
pattern = re.compile(r"pattern", flags)
# 测试
pattern.match(string) # 从开始匹配
pattern.search(string) # 搜索第一个匹配
pattern.fullmatch(string) # 完整匹配
# 匹配所有
pattern.findall(string) # 返回列表
pattern.finditer(string) # 返回迭代器
# 替换
pattern.sub(replacement, string)
pattern.subn(replacement, string) # 返回 (新字符串, 替换次数)
# 分割
pattern.split(string)
# 常用标志
# re.I / re.IGNORECASE - 忽略大小写
# re.M / re.MULTILINE - 多行模式
# re.S / re.DOTALL - . 匹配换行
# re.X / re.VERBOSE - 详细模式(忽略空白和注释)
# re.A / re.ASCII - ASCII 模式
Java
import java.util.regex.*;
// 创建模式
Pattern pattern = Pattern.compile("regex", flags);
Matcher matcher = pattern.matcher(input);
// 测试
matcher.matches(); // 完整匹配
matcher.find(); // 查找下一个匹配
matcher.lookingAt(); // 从开始匹配
// 获取结果
matcher.group(); // 完整匹配
matcher.group(1); // 第1个分组
matcher.group("name"); // 命名分组
// 替换
matcher.replaceAll(replacement);
matcher.replaceFirst(replacement);
// 常用标志
// Pattern.CASE_INSENSITIVE - 忽略大小写
// Pattern.MULTILINE - 多行模式
// Pattern.DOTALL - . 匹配换行
// Pattern.UNICODE_CASE - Unicode 大小写
Go
package main
import (
"fmt"
"regexp"
)
func main() {
// 创建正则
re := regexp.MustCompile(`pattern`)
// 测试
re.MatchString(string) // 返回 bool
re.Match([]byte) // 返回 bool
// 查找
re.FindString(string) // 返回第一个匹配或空字符串
re.FindAllString(string, n) // 返回所有匹配(n=-1 表示所有)
re.FindStringSubmatch(string) // 返回分组匹配
// 替换
re.ReplaceAllString(string, replacement)
re.ReplaceAllStringFunc(string, func(string) string)
// 分割
re.Split(string, n)
}
性能优化建议
1. 避免回溯灾难
// 坏:重叠量词导致指数级回叩
/(a+)+b/.test("aaaaaaaaaaaaaaaaaaaaaaaaaaaa!");
// 好:使用具体的字符类
/a+b/.test("aaaaaaaaaaaaaaaaaaaaaaaaaaaa!");
2. 使用具体的字符类
// 较慢
/.*?/
// 较快
/[^\n]*?/
3. 预编译模式
import re
# 坏:每次都重新编译
for text in texts:
re.match(r"\d+", text)
# 好:预先编译
pattern = re.compile(r"\d+")
for text in texts:
pattern.match(text)
4. 使用锚点限制搜索范围
// 如果确知模式在开始位置
/^\d+/.exec(str); // 比 /\d+/ 更快
调试工具
常见错误
| 错误 | 原因 | 解决 |
|---|---|---|
. 不匹配换行 | 默认行为 | 使用 [\s\S] 或 s 标志 |
* 和 + 过度匹配 | 贪婪匹配 | 使用非贪婪量词 *? +? |
| 特殊字符未转义 | $ * 等有特殊含义 | 使用 \ 转义 |
字符类中 - 的位置 | - 在中间表示范围 | 将 - 放在开头或结尾 |
| Unicode 字符问题 | \w 等不匹配中文 | 使用 \p{Han} 或 Unicode 范围 |