JavaScript正则表达式是什么_如何进行模式匹配

JavaScript正则表达式由RegExp构造函数和字面量语法支持,字面量复用实例而构造函数每次新建;test()在g标志下因lastIndex状态导致“跳着匹配”,需重置或改用match()。

JavaScript 正则表达式是内置的模式匹配引擎,不是字符串方法,也不是第三方库——它由 RegExp 构造函数和字面量语法/pattern/flags)共同支撑,直接集成在语言运行时中。

怎么创建一个正则表达式对象

两种方式等价,但行为细节有差异:

  • 字面量写法:/\d{3}-\d{4}/ —— 每次出现都复用同一个实例,适合静态、固定模式;多次调用 .test() 时若带 g 标志,会因内部 lastIndex 状态导致结果不一致
  • 构造函数写法:new RegExp('\\d{3}-\\d{4}', 'g') —— 每次执行都新建实例,适合动态拼接模式(比如用户输入的关键词),注意反斜杠要双写(字符串转义一次,正则再转义一次)

为什么 test() 在全局模式下会“跳着匹配”

这是 RegExp.prototype.test()g 标志配合时最常踩的坑:它会修改正则对象的 lastIndex 属性,下次调用从上次结束位置继续搜,而不是重头开始。

例如:

const r = /a/g;
console.log(r.test('abca')); // true
console.log(r.test('abca')); // true(从索引 2 开始,匹配到第 3 个 a)
console.log(r.test('abca')); // false(lastIndex 已超长度)

解决办法:
- 不需要全局匹配时,去掉 g
- 必须用 g 且反复测试同一字符串,每次调用前手动重置:r.lastIndex = 0
- 改用 String.prototype.match(),它不改变正则状态,返回数组或 null

常见匹配场景与对应写法

实际开发中高频需求,直接对应到具体方法和标志:

  • 校验邮箱格式(简单版):/^[^\s@]+@[^\s@]+\.[^\s@]+$/,用 .test() 即可,不需要 g
  • 提取所有数字:str.match(/\d+/g) —— g 不可少,否则只返回第一个匹配项及其额外信息(index、input 等)
  • 忽略大小写替换:str.replace(/hello/gi, 'hi')i 处理大小写,g 确保全串替换
  • 捕获分组提取内容:'2025-04-01'.match(/(\d{4})-(\d{2})-(\d{2})/) 返回数组,[0] 是完整匹配,[1][2][3] 是各括号内容

真正难的不是写出一个能跑的正则,而是理解它在不同方法(test/exec/match/replace)下的状态表现、边界行为和性能代价。尤其当模式变长、嵌套或含回溯时,lastIndex、标志组合、字符串长度三者一碰就容易出隐性 bug。