一、基础元字符
字符
含义
示例
.
任意单个字符(除换行)
a.c → abc, a1c
\d
数字 [0-9]
\d{3} → 123
\D
非数字 [^0-9]
\D+ → abc
\w
单词字符 [a-zA-Z0-9_]
\w+ → hello_world
\W
非单词字符
\W → @, #,
\s
空白字符(空格、Tab、换行)
\s+ →
\S
非空白字符
\S+ → abc
\b
单词边界
\bword\b 精确匹配 word
\B
非单词边界
二、量词(匹配次数)
量词
含义
等价写法
*
0 次或多次
{0,}
+
1 次或多次
{1,}
?
0 次或 1 次
{0,1}
{n}
恰好 n 次
\d{3} → 123
{n,}
至少 n 次
\w{3,}
{n,m}
n 到 m 次
\d{3,8}
三、字符类与范围
1 2 3 4 5 6 7 [abc] [^abc] [a-z] [A-Z] [0 -9 ] [a-zA-Z] [a-zA-Z0 -9_]
在 [] 内,大部分特殊字符失去特殊含义 :
四、边界与位置
符号
含义
^
字符串开头(多行模式下是行首)
$
字符串结尾(多行模式下是行尾)
\b
单词边界
\B
非单词边界
(?=...)
正向前瞻
(?!...)
负向前瞻
(?<=...)
正向后顾(ES2018)
(?<!...)
负向后顾(ES2018)
1 2 3 4 5 /[a-zA-Z]+(?=Script )/g.exec ('JavaScript' ); /(?<=\$)\d+/ .exec ('Price: $100' );
五、分组与捕获
语法
含义
(...)
捕获分组
(?:...)
非捕获分组(不保存到结果)
\1, \2
反向引用第 n 个分组
(?<name>...)
命名捕获组(ES2018)
1 2 3 4 5 6 7 let re = /^(?<area>\d{3})-(?<number>\d{3,8})$/ ;let result = re.exec ('010-12345' );console .log (result.groups .area ); console .log (result.groups .number ); /\b(\w+)\s+\1\b/ .test ('hello hello' );
六、贪婪 vs 非贪婪
模式
符号
行为
贪婪(默认)
*, +, ?, {n,m}
尽可能多匹配
非贪婪
*?, +?, ??, {n,m}?
尽可能少匹配
1 2 3 4 let html = '<div>content</div><span>text</span>' ;/<.*>/ .exec (html)[0 ]; /<.*?>/ .exec (html)[0 ];
七、JavaScript 正则标志(Flags)
| 标志 | 含义 | 说明 |----------- |
| g | global 全局匹配 | exec() 多次调用,更新 lastIndex |
| i | ignoreCase 忽略大小写 | |
| m | multiline 多行模式 | ^$ 匹配每行开头结尾 |
| s | dotAll 单行模式 | . 匹配换行符(ES2018) |
| u | unicode Unicode 模式 | 正确处理 Unicode(ES2015) |
| y | sticky 粘性匹配 | 从 lastIndex 开始严格匹配(ES2015) |
1 2 3 4 5 let re = /test/gi ; let re2 = new RegExp ('test' , 'gi' ); /foo.bar/ s.test ('foo\nbar' );
八、JS 正则 API
1. RegExp.prototype.test(str) — 布尔判断
1 2 /^\d+$/.test ('123' ); /^\d+$/ .test ('abc' );
2. RegExp.prototype.exec(str) — 提取匹配
1 2 3 4 5 6 7 let re = /(\d{3})-(\d{3,8})/ ;let result = re.exec ('010-12345' );
3. String.prototype.match(regexp) — 匹配数组
1 2 3 4 5 'abc123def456' .match (/\d+/g ); '010-12345' .match (/(\d{3})-(\d{3,8})/ );
4. String.prototype.matchAll(regexp) — 迭代所有匹配(ES2020)
1 2 3 4 5 6 let str = 'JavaScript, VBScript, JScript' ;let re = /[a-zA-Z]+Script/g ;for (const match of str.matchAll (re)) { console .log (match[0 ]); }
5. String.prototype.search(regexp) — 查找位置
1 2 'hello world' .search (/world/ ); 'hello world' .search (/xyz/ );
6. String.prototype.replace(regexp, replacement) — 替换
1 2 3 4 5 6 7 '2024-06-20' .replace (/-/g , '/' ); '010-12345' .replace (/(\d{3})-(\d{3,8})/ , '($1) $2' ); 'abc123def456' .replace (/\d+/g , match => `[${match} ]` );
7. String.prototype.split(separator) — 分割
1 'a,b;; c d' .split (/[\s,;]+/ );
九、实用正则大全
Email(基础版)
1 /^[a-zA-Z0 -9. _%+-]+@[a-zA-Z0 -9. -]+\.[a-zA-Z]{2 ,}$/
手机号(中国大陆)
身份证号
1 2 /^\d{15 }|\d{18 }$/ /^[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]$/
URL
1 /^https?:\/\/[a-zA-Z0 -9. -]+\.[a-zA-Z]{2 ,}(\/\S*)?$/
中文字符
1 2 /[\u4e00-\u9fa5]+/ / / 基础中文 / \p{Script =Han }/u
密码强度(8-20位,至少包含字母和数字)
1 /^(?=.*[A-Za -z])(?=.*\d)[A-Za -z\d@$!%*?&]{8 ,20 }$/
去除 HTML 标签
1 html.replace (/<[^>]+>/g , '' )
提取 Markdown 链接
1 /\[([^\]]+)\]\(([^)]+)\)/g
十、性能优化与陷阱
陷阱
说明
解决
回溯灾难
(a+)+b 匹配超长字符串时指数级回溯
使用原子组(JS 不支持)或简化模式
贪婪导致过度匹配
.* 匹配太多
用 .*? 非贪婪,或限定范围
Unicode 问题
\w 不匹配中文
用 [\u4e00-\u9fa5] 或 \p{L}(u 标志)
多行匹配
^$ 默认只匹配首尾
加 m 标志
lastIndex 陷阱
带 g 标志的 RegExp 会记住位置
每次 test/exec 前重置 lastIndex = 0
1 2 3 4 5 let re = /\d+/g ;re.test ('123' ); re.test ('123' ); re.lastIndex = 0 ; re.test ('123' );
十一、ES 新特性时间线
特性
版本
说明
u (Unicode)
ES2015
\u{1F600} 正确匹配 Emoji
y (Sticky)
ES2015
粘性匹配
s (dotAll)
ES2018
. 匹配换行
命名捕获组 (?<name>)
ES2018
result.groups.name
后顾断言 (?<=) (?<!)
ES2018
向前/向后查找
matchAll
ES2020
返回迭代器,替代 while + exec
十二、一句话总结
正则本质是"模式描述语言":用元字符描述规则,用量词控制次数,用分组提取信息,用标志控制行为。JS 中优先用字面量 /.../,需动态构建时用 new RegExp()。复杂场景(如 Email 完整验证)建议用专业库,正则负责简单高效的匹配。
一个示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 let re = /^\d{3}-\d{3,8}$/ ;console .log (re.test ('010-12345' )); console .log (re.test ('010-1234x' )); console .log (re.test ('010 12345' )); console .log ('a b c' .split (/\s+/ )); re = /^(\d{3})-(\d{3,8})$/ ; console .log (re.exec ('010-12345' )); console .log (re.exec ('010 12345' )); re = /^(\d+)(0*)$/ ; console .log (re.exec ('102300' )); re = /^(\d+?)(0*)$/ ; console .log (re.exec ('102300' ));
参考