JavaScript正则表达式
1. 概览介绍
正则表达式(Regular Expression,简称 regex 或 regexp)是一种强大的文本模式匹配工具,在 JavaScript 中用于:
- 验证字符串格式(如邮箱、手机号)
- 查找和提取特定内容
- 替换文本中的特定部分
- 分割字符串
在 JavaScript 中,正则表达式可以通过两种方式创建:
- 字面量语法:
/pattern/flags - RegExp 构造函数:
new RegExp("pattern", "flags")
2. 创建方式
2.1 字面量语法
javascript
// 匹配字符串中的 "hello",不区分大小写
const regex = /hello/i;
console.log(regex.test("Hello World")); // true
2.2 构造函数
javascript
// 动态创建正则表达式
const pattern = "hello";
const flags = "i";
const regex = new RegExp(pattern, flags);
console.log(regex.test("Hello World")); // true
2.3 两种方式的区别
| 特性 | 字面量语法 | RegExp 构造函数 |
|---|---|---|
| 写法 | /pattern/flags |
new RegExp("pattern", "flags") |
| 模式类型 | 静态(编译时确定) | 动态(运行时确定) |
| 特殊字符 | 需直接转义 | 需双重转义 |
| 适用场景 | 模式固定时 | 模式需要动态生成时 |
3. 标志(Flags)
正则表达式可以使用以下标志来修改匹配行为:
| 标志 | 描述 | 示例 |
|---|---|---|
g |
全局匹配,找到所有匹配项 | /a/g 匹配 “abcabc” 中的所有 “a” |
i |
不区分大小写 | /A/i 匹配 “a” 和 “A” |
m |
多行模式,^ 和 $ 匹配每行的开头和结尾 |
/^a/m 匹配 “abc\ndef” 中的 “a” |
s |
点号匹配换行符(ES9+) | /a.b/s 匹配 “a\nb” |
u |
Unicode 模式,正确处理 Unicode 字符 | /\u{1F600}/u 匹配笑脸表情 😀 |
y |
粘性匹配,从 lastIndex 开始匹配 |
const regex = /a/y; regex.lastIndex = 1; regex.test("abc") 返回 true |
4. 正则表达式模式语法
4.1 字符匹配
普通字符
普通字符直接匹配自身,如 a 匹配字符串中的 “a”。
转义字符
使用反斜杠 \ 转义特殊字符:
\n:换行符\t:制表符\.:匹配点号本身\\:匹配反斜杠本身
字符集合
[abc]:匹配 “a”、“b” 或 “c”[a-z]:匹配任意小写字母[A-Z]:匹配任意大写字母[0-9]:匹配任意数字[^abc]:匹配除 “a”、“b”、“c” 之外的任意字符
4.2 预定义字符类
| 字符 | 描述 | 等价于 |
|---|---|---|
. |
匹配除换行符外的任意字符 | [^\n\r] |
\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] |
4.3 边界匹配
| 字符 | 描述 |
|---|---|
^ |
匹配字符串或行的开头 |
$ |
匹配字符串或行的结尾 |
\b |
匹配单词边界(字母与非字母之间) |
\B |
匹配非单词边界 |
示例:
javascript
/^hello/.test("hello world"); // true,hello 在开头
/hello$/.test("say hello"); // true,hello 在结尾
/\bworld\b/.test("hello world"); // true,world 是完整单词
/\bworld\b/.test("helloworld"); // false,world 不是完整单词
4.4 量词
| 量词 | 描述 | 示例 |
|---|---|---|
* |
匹配 0 次或多次 | a* 匹配 “”, “a”, “aa” 等 |
+ |
匹配 1 次或多次 | a+ 匹配 “a”, “aa” 等,不匹配 “” |
? |
匹配 0 次或 1 次 | a? 匹配 “” 或 “a” |
{n} |
匹配恰好 n 次 | a{3} 仅匹配 “aaa” |
{n,} |
匹配至少 n 次 | a{2,} 匹配 “aa”, “aaa” 等 |
{n,m} |
匹配 n 到 m 次 | a{1,3} 匹配 “a”, “aa”, “aaa” |
贪婪模式与惰性模式
- 贪婪模式:默认情况下,量词会尽可能匹配更多字符
- 惰性模式:在量词后添加
?,使其尽可能匹配更少字符
javascript
const str = "<div>content1</div><div>content2</div>";
// 贪婪模式:匹配从第一个 <div> 到最后一个 </div>
str.match(/<div>.*<\/div>/); // ["<div>content1</div><div>content2</div>"]
// 惰性模式:匹配第一个 <div> 和其对应的 </div>
str.match(/<div>.*?<\/div>/); // ["<div>content1</div>"]
4.5 分组与捕获
捕获组
使用括号 () 创建捕获组,捕获匹配的内容:
javascript
const regex = /(\d{4})-(\d{2})-(\d{2})/;
const match = regex.exec("2023-10-05");
// match[0]: "2023-10-05"(完整匹配)
// match[1]: "2023"(第一个捕获组)
// match[2]: "10"(第二个捕获组)
// match[3]: "05"(第三个捕获组)
非捕获组
使用 (?:...) 创建非捕获组,仅用于分组,不捕获内容:
javascript
const regex = /(?:https?:\/\/)?(www\.[^\s]+)/;
const match = regex.exec("https://www.example.com");
// match[0]: "https://www.example.com"
// match[1]: "www.example.com"(只有一个捕获组)
命名捕获组(ES9+)
使用 (?<name>...) 为捕获组命名:
javascript
const regex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = regex.exec("2023-10-05");
// match.groups.year: "2023"
// match.groups.month: "10"
// match.groups.day: "05"
反向引用
使用 \1, \2 等引用之前的捕获组,或 \k<name> 引用命名捕获组:
javascript
// 匹配重复的单词
const regex = /\b(\w+)\s+\1\b/;
regex.test("hello hello"); // true
// 使用命名捕获组的反向引用
const regex2 = /(?<word>\w+)\s+\k<word>/;
regex2.test("hello hello"); // true
4.6 断言
断言用于检查匹配位置的前后内容,但不包含在匹配结果中。
先行断言
(?=...):正向先行断言,匹配后面跟着特定内容的位置(?!...):负向先行断言,匹配后面不跟着特定内容的位置
javascript
// 匹配后面跟着 "@example.com" 的用户名
const regex = /\w+(?=@example\.com)/;
regex.exec("user@example.com"); // ["user"]
// 匹配后面不跟着数字的单词
const regex2 = /\w+(?!\d)/;
regex2.exec("hello123"); // ["hello"]
后行断言(ES9+)
(?<=...):正向后行断言,匹配前面跟着特定内容的位置(?<!...):负向后行断言,匹配前面不跟着特定内容的位置
javascript
// 匹配前面是 "$" 的数字
const regex = /(?<=\$)\d+/;
regex.exec("Price: $100"); // ["100"]
// 匹配前面不是 "$" 的数字
const regex2 = /(?<!\$)\d+/;
regex2.exec("Price: 100"); // ["100"]
4.7 选择分支
使用 | 表示或关系:
javascript
// 匹配 "cat" 或 "dog"
const regex = /cat|dog/;
regex.test("I have a cat"); // true
regex.test("I have a dog"); // true
⚠️ 注意:选择分支是惰性的,匹配到第一个符合条件的分支就会停止。
5. RegExp 对象的方法与属性
5.1 方法
test(str)
检查字符串是否匹配正则表达式,返回布尔值:
javascript
const regex = /hello/;
regex.test("Hello World"); // false(区分大小写)
regex.test("hello world"); // true
exec(str)
查找匹配项,返回匹配结果数组或 null:
javascript
const regex = /(\d{4})-(\d{2})-(\d{2})/;
const result = regex.exec("Today is 2023-10-05");
// result: ["2023-10-05", "2023", "10", "05", index: 9, input: "Today is 2023-10-05", groups: undefined]
5.2 属性
| 属性 | 描述 | 示例 |
|---|---|---|
flags |
返回正则表达式的所有标志 | /abc/gim.flags 返回 “gim” |
global |
是否启用全局匹配 | /abc/g.global 返回 true |
ignoreCase |
是否忽略大小写 | /abc/i.ignoreCase 返回 true |
multiline |
是否启用多行模式 | /abc/m.multiline 返回 true |
source |
返回正则表达式的模式字符串 | /abc/g.source 返回 “abc” |
lastIndex |
下一次匹配的起始位置(仅全局模式有效) | /a/g.lastIndex |
6. String 中与正则相关的方法
6.1 match()
查找匹配项,返回匹配结果数组或 null:
javascript
const str = "abcabc";
str.match(/a/); // ["a", index: 0, input: "abcabc", groups: undefined]
str.match(/a/g); // ["a", "a"](全局模式返回所有匹配项)
6.2 matchAll()(ES9+)
返回所有匹配项的迭代器:
javascript
const str = "abcabc";
const matches = [...str.matchAll(/a/g)];
// matches: [
// ["a", index: 0, input: "abcabc", groups: undefined],
// ["a", index: 3, input: "abcabc", groups: undefined]
// ]
6.3 search()
查找第一个匹配项的索引,返回索引或 -1:
javascript
const str = "abcabc";
str.search(/a/); // 0
str.search(/z/); // -1
6.4 replace()
替换匹配项:
javascript
const str = "hello world";
str.replace(/world/, "JavaScript"); // "hello JavaScript"
// 使用函数作为替换值
str.replace(/\w+/g, (match) => match.toUpperCase()); // "HELLO WORLD"
6.5 replaceAll()(ES9+)
替换所有匹配项(无需使用 g 标志):
javascript
const str = "abcabc";
str.replaceAll("a", "x"); // "xbcxbc"
6.6 split()
根据匹配项分割字符串:
javascript
const str = "a,b,c";
str.split(","); // ["a", "b", "c"]
// 使用正则表达式分割
const str2 = "a1b2c3";
str2.split(/\d+/); // ["a", "b", "c"]
7. 常用正则示例
7.1 邮箱验证
javascript
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
emailRegex.test("user@example.com"); // true
emailRegex.test("invalid-email"); // false
7.2 URL 提取
javascript
const urlRegex = /https?:\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/g;
const text = "Visit https://www.example.com and http://test.org";
text.match(urlRegex); // ["https://www.example.com", "http://test.org"]
7.3 手机号格式(中国大陆)
javascript
const phoneRegex = /^1[3-9]\d{9}$/;
phoneRegex.test("13812345678"); // true
phoneRegex.test("12345678901"); // false(开头不是13-19)
7.4 密码强度规则(至少8位,包含字母和数字)
javascript
const passwordRegex = /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/;
passwordRegex.test("password123"); // true
passwordRegex.test("password"); // false(没有数字)
passwordRegex.test("12345678"); // false(没有字母)
7.5 提取 HTML 标签内容
javascript
const htmlRegex = /<([a-z]+)>(.*?)<\/\1>/;
const html = "<div>content</div>";
html.match(htmlRegex); // ["<div>content</div>", "div", "content"]
7.6 日期格式匹配(YYYY-MM-DD)
javascript
const dateRegex = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/;
dateRegex.test("2023-10-05"); // true
dateRegex.test("2023-13-05"); // false(月份无效)
dateRegex.test("2023-10-32"); // false(日期无效)
8. 性能与最佳实践
8.1 避免灾难性回溯
复杂的嵌套量词可能导致灾难性回溯,影响性能:
javascript
// 不推荐:可能导致性能问题
const badRegex = /(a+)+$/;
const str = "aaaaa";
// badRegex.test(str); // 可能会卡住
// 推荐:简化正则表达式
const goodRegex = /a+$/;
8.2 预编译常用正则
对于重复使用的正则表达式,使用字面量语法预编译:
javascript
// 预编译正则表达式
const regex = /\w+/g;
// 多次使用
for (let i = 0; i < 1000; i++) {
regex.test(`test${i}`);
}
8.3 使用非捕获组提升性能
如果不需要捕获匹配内容,使用非捕获组 (?:...):
javascript
// 不推荐:使用了不必要的捕获组
const badRegex = /(abc)+/;
// 推荐:使用非捕获组
const goodRegex = /(?:abc)+/;
8.4 注意 Unicode 字符处理
使用 u 标志正确处理 Unicode 字符:
javascript
// 匹配 Unicode 表情
const regex = /\u{1F600}/u;
regex.test("😀"); // true
8.5 优先使用简单模式
能用简单正则解决的问题,不要使用复杂正则:
javascript
// 不推荐:使用复杂正则匹配固定字符串
const badRegex = /^hello$/;
// 推荐:直接使用字符串比较
const str = "hello";
str === "hello";
9. 浏览器兼容性与 ES 新特性
| 特性 | ES 版本 | 浏览器支持 |
|---|---|---|
命名捕获组 (?<name>...) |
ES9 (2018) | Chrome 64+, Firefox 78+, Safari 11.1+ |
后行断言 (?<=...)、(?<!...) |
ES9 (2018) | Chrome 64+, Firefox 78+, Safari 12+ |
s 标志(dotAll) |
ES9 (2018) | Chrome 62+, Firefox 78+, Safari 12+ |
matchAll() |
ES9 (2018) | Chrome 63+, Firefox 67+, Safari 13+ |
replaceAll() |
ES11 (2020) | Chrome 85+, Firefox 77+, Safari 13.1+ |
9.1 替代方案与 Polyfill
对于不支持新特性的浏览器,可以使用以下方法:
- 使用 Babel 转译新的正则语法
- 使用 polyfill 实现新方法(如
matchAll、replaceAll) - 手动实现 复杂功能(如后行断言)
10. 调试与工具推荐
10.1 在线测试工具
- Regex101:https://regex101.com/ - 支持 JavaScript,提供详细的匹配说明
- RegExr:https://regexr.com/ - 可视化正则表达式,支持实时测试
- RegEx Pal:https://www.regexpal.com/ - 简单易用的正则测试工具
10.2 浏览器控制台调试
使用浏览器控制台调试正则表达式:
javascript
const regex = /(\d+)-(\w+)/;
const str = "123-abc";
// 使用 exec() 查看详细匹配信息
console.log(regex.exec(str));
// 使用 test() 快速验证
console.log(regex.test(str));
// 查看正则表达式的属性
console.log(regex.flags);
console.log(regex.source);
10.3 可视化工具
- RegEx Vis:https://regex-vis.com/ - 将正则表达式可视化,便于理解复杂模式
- Debuggex:https://www.debuggex.com/ - 正则表达式可视化工具
延伸阅读
最后更新:2026-02-05