JavaScript中的正则表达式
JavaScript 通过内置对象 RegExp 支持正则表达式,同时字符串方法也提供了正则相关的操作。本文将详细介绍在 JavaScript 中使用正则表达式的各种方式、方法区别以及注意事项。
创建正则表达式
有两种方式创建正则对象:
- 字面量:使用斜杠包裹模式,后跟可选标志。例如:
const re = /abc/gi; - 构造函数:
new RegExp("abc", "gi")。当模式需要动态生成时使用构造函数。
正则对象的方法
1. exec()
在字符串中执行匹配,返回一个数组(包含匹配信息及分组)或 null。如果正则带有 g 标志,每次调用 exec 会从上一次匹配的 lastIndex 开始继续查找。
const re = /\d+/g;
const str = "abc123def456";
let match;
while ((match = re.exec(str)) !== null) {
console.log(`匹配到 ${match[0]} 在索引 ${match.index}`);
}
2. test()
测试字符串是否匹配模式,返回布尔值。常用于表单验证。
if (/^\d+$/.test("123")) {
console.log("全是数字");
}
字符串方法中使用正则
1. match()
返回字符串匹配正则的结果。
- 如果正则没有
g标志,match()返回和exec()相同的结果数组(包含分组)。 - 如果有
g标志,返回一个包含所有匹配项的数组(不包含分组)。
"a1b2c3".match(/\d/g); // ["1", "2", "3"]
2. matchAll() (ES2020)
返回一个迭代器,包含所有匹配结果(包括分组),需要正则带有 g 标志。比 while(exec) 更方便。
const matches = "a1b2c3".matchAll(/(\d)/g);
for (const m of matches) {
console.log(m[0], m[1]); // 输出数字和捕获组
}
3. search()
返回第一个匹配项的索引,如果找不到返回 -1。
"Hello World".search(/World/); // 6
4. replace()
替换匹配的子串。第二个参数可以是字符串或函数。字符串中可以使用 $n 引用分组。
"2025-03-18".replace(/(\d{4})-(\d{2})-(\d{2})/, "$3/$2/$1"); // "18/03/2025"
使用函数:
"abc123".replace(/\d+/, function(match) {
return parseInt(match) * 2;
}); // "abc246"
5. replaceAll() (ES2021)
替换所有匹配项,相当于 replace 配合全局正则,但更直观。
"1 2 3".replaceAll(/\d/g, "x"); // "x x x"
6. split()
用正则分隔字符串。
"a,b c,d".split(/[,\s]+/); // ["a", "b", "c", "d"]
标志(Flags)详解
| 标志 | 描述 |
|---|---|
g | 全局匹配,查找所有匹配项,而不是在第一个之后停止。 |
i | 忽略大小写。 |
m | 多行模式,^ 和 $ 匹配每行的开始和结束(而不是整个字符串)。 |
s | 单行模式,让 . 匹配包括换行符在内的所有字符(ES2018)。 |
u | Unicode 模式,将模式视为 Unicode 代码点序列,正确处理大于 uFFFF 的字符。 |
y | 粘附模式,从 lastIndex 位置开始匹配,如果该位置不匹配则失败。 |
正则表达式中的特殊字符转义
在构造函数中使用字符串时,需要对反斜杠进行转义,例如 new RegExp("\\d+")。而字面量写法更简单直观,推荐优先使用。
性能注意事项
- 避免在循环中创建正则对象,尤其是字面量,应重用对象。
- 复杂的正则可能导致灾难性回溯,尽量使用原子组(但 JavaScript 不支持原子组,可以通过某些技巧模拟)。
- 大量使用
exec循环时,注意重置lastIndex或使用matchAll。
常见陷阱
- lastIndex 在非全局模式无效:只有全局或粘附模式才影响
exec的起始位置。 - test 和 exec 共享 lastIndex:使用全局正则时,交替调用
test和exec可能互相影响,需小心。 - Unicode 匹配:使用
/.../u才能正确匹配如 😀 这样的字符(否则会被当作两个字符)。
综合示例
// 验证密码强度:至少8位,包含大小写字母和数字
function validatePassword(pwd) {
const re = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[A-Za-z\d]{8,}$/;
return re.test(pwd);
}
// 提取所有标签名
function extractTagNames(html) {
const re = /<([a-z]+)[^>]*>/gi;
return Array.from(html.matchAll(re), m => m[1]);
}
掌握以上内容,您就可以在 JavaScript 项目中熟练运用正则表达式解决各种字符串处理问题。