[!info] related notes
正则表达式速查
基本元字符
| 元字符 | 描述 | 示例 |
|---|
. | 匹配除换行符外的任意单个字符 | a.c 匹配 “abc”、“adc” 等 |
^ | 匹配行的开始 | ^abc 匹配以 “abc” 开头的行 |
$ | 匹配行的结束 | abc$ 匹配以 “abc” 结尾的行 |
* | 匹配前面的字符 0 次或多次 | ab*c 匹配 “ac”、“abc”、“abbc” 等 |
+ | 匹配前面的字符 1 次或多次 | ab+c 匹配 “abc”、“abbc” 等 |
? | 匹配前面的字符 0 次或 1 次 | ab?c 匹配 “ac”、“abc” |
\ | 转义字符 | \. 匹配点号字符 |
字符类
| 字符类 | 描述 | 示例 |
|---|
[abc] | 匹配方括号中的任意字符 | [abc] 匹配 “a”、“b” 或 “c” |
[^abc] | 匹配除方括号中字符外的任意字符 | [^abc] 匹配除 “a”、“b”、“c” 外的字符 |
[a-z] | 匹配指定范围内的任意字符 | [a-z] 匹配任意小写字母 |
\d | digit 匹配任意数字,等价于 [0-9] | \d+ 匹配一个或多个数字 |
\w | word 匹配字母、数字、下划线,等价于 [a-zA-Z0-9_] | \w+ 匹配一个或多个单词字符 |
\s | space 匹配任意空白字符(空格、制表符、换行符) | \s+ 匹配一个或多个空白字符 |
量词
| 量词 | 描述 | 示例 |
|---|
{n} | 精确匹配 n 次 | a{3} 匹配 “aaa” |
{n,} | 匹配至少 n 次 | a{2,} 匹配 “aa”、“aaa” 等 |
{n,m} | 匹配 n 到 m 次 | a{2,4} 匹配 “aa”、“aaa”、“aaaa” |
* | 匹配 0 次或多次,等价于 {0,} | ab* 匹配 “a”、“ab”、“abb” 等 |
+ | 匹配 1 次或多次,等价于 {1,} | ab+ 匹配 “ab”、“abb” 等 |
? | 匹配 0 次或 1 次,等价于 {0,1} | ab? 匹配 “a”、“ab” |
分组和引用
| 语法 | 描述 | 示例 |
|---|
(...) | 捕获组,创建一个子表达式 | (ab)+ 匹配 “ab”、“abab” 等 |
(?:...) | 非捕获组,不创建子表达式 | (?:ab)+ 同上,但不捕获 |
(?<name>...) | 命名捕获组 | (?<year>\d{4}) 后通过 m.groups.year 访问 |
\1, \2 | 反向引用,引用之前的捕获组 | (a)\1 匹配 “aa” |
\k<name> | 命名反向引用 | (?<w>\w+)\s+\k<w> 匹配重复单词 |
命名分组示例
const reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const m = "2026-03-21".match(reg);
m.groups.year; // "2026"
m.groups.month; // "03"
反向引用示例
/<(\w+)>.*?<\/\1>/ // 匹配成对 HTML 标签
/^(\w+)\s+\1$/ // "hello hello" ✓, "hello world" ✗
贪婪与非贪婪
| 贪婪 | 非贪婪 | 含义 |
|---|
* | *? | 0 次或多次(尽量少) |
+ | +? | 1 次或多次(尽量少) |
? | ?? | 0 次或 1 次(尽量少) |
{n,m} | {n,m}? | n 到 m 次(尽量少) |
默认量词是贪婪的(尽量多吃),加 ? 变非贪婪(尽量少吃)。
详见:regex-greedy-vs-non-greedy
边界
| 语法 | 描述 | 示例 |
|---|
^ | 字符串开头(m 模式下匹配行首) | ^abc |
$ | 字符串结尾(m 模式下匹配行尾) | abc$ |
\b | 单词边界 | \bcat\b 不匹配 “catalog” |
\B | 非单词边界 | \Bcat\B 匹配 “concatenate” 中的 “cat” |
断言
| 语法 | 名称 | 描述 |
|---|
(?=...) | 正向先行 | 后面必须跟 ... |
(?!...) | 负向先行 | 后面不能跟 ... |
(?<=...) | 正向后行 | 前面必须跟 ... |
(?<!...) | 负向后行 | 前面不能跟 ... |
示例
// 匹配后面跟 "px" 的数字(不含 px)
"12px".match(/\d+(?=px)/); // ["12"]
// 匹配 "$" 后面的数字(不含 $)
"$199".match(/(?<=\$)\d+/); // ["199"]
// 匹配后面不跟 "px" 的数字
"12px 30em".match(/\d+(?!px)/);
详见:regex-lookahead-lookbehind
常用标志
| 标志 | 描述 | 示例 |
|---|
g | global 全局搜索 | /a/g 匹配所有 a |
i | ignore 忽略大小写 | /abc/i 匹配 ABC |
m | multiline 多行模式(^ $ 匹配每行) | /^a/m |
s | dotAll 点号匹配所有字符(包括换行符) | /a.b/s |
u | Unicode 模式,按 Unicode 语义处理 | /\p{Letter}/u |
y | sticky 粘连匹配,从 lastIndex 开始必须紧接着匹配 | /\d/y |
[!warning] g 标志的状态陷阱
带 g 的正则有状态,test() / exec() 反复调用受 lastIndex 影响。
详见:regex-lastindex-pitfall
常用示例
| 用途 | 正则表达式 | 说明 |
|---|
| 邮箱 | ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ | 匹配电子邮件地址 |
| 手机号 | ^1[3-9]\d{9}$ | 匹配中国大陆手机号 |
| URL | ^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$ | 匹配 URL |
| IP地址 | `^(?:(?:25[0-5] | 2[0-4][0-9] |
| 身份证号 | `^[1-9]\d{5}(19 | 20)\d{2}(0[1-9] |
| 中文字符 | ^[\u4e00-\u9fa5]+$ | 匹配中文字符 |
| 邮政编码 | ^[1-9]\d{5}$ | 匹配中国邮政编码 |
| QQ号 | ^[1-9][0-9]{4,}$ | 匹配QQ号 |
| 微信号 | ^[a-zA-Z][-_a-zA-Z0-9]{5,19}$ | 匹配微信号 |
| 车牌号 | ^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤川青藏琼宁][A-HJ-NP-Z][A-HJ-NP-Z0-9]{4,5}[A-HJ-NP-Z0-9挂学警港澳]$ | 匹配中国车牌号 |
使用过的示例
添加一级标题
查找 ^(#+)
替换 $1#
每行后面加两行
查找 (.+)
替换 $1\n\n
获取所有 console.log() 代码
^\s*console\.log\(.*\);
提取所有价格
const text = "apple: $12, banana: $7, orange: $105";
text.match(/\$(\d+)/g); // ["$12", "$7", "$105"]
日期格式转换
"2026-03-21".replace(/(\d{4})-(\d{2})-(\d{2})/, "$2/$3/$1");
// "03/21/2026"
匹配重复单词
/\b(\w+)\s+\1\b/g
// "hi hi" ✓, "hello world" ✗
匹配简单邮箱
/^[\w.-]+@[\w.-]+\.[A-Za-z]{2,}$/
匹配中国大陆手机号
/^1[3-9]\d{9}$/
去掉首尾空白
str.replace(/^\s+|\s+$/g, "")
// 等价于 str.trim()
把多个空格合成一个
str.replace(/\s+/g, " ")