JS 正则标志位与粘性匹配
标志位决定搜索方式与字符处理方式:全局与粘性影响「从哪里开始、找几次」,忽略大小写与多行影响语义,点号匹配换行与 Unicode 模式影响字符解释,区间标志额外提供匹配位置。其中粘性标志最容易被忽略——它要求从当前位置精确匹配,不向前搜索,行为与全局标志并不等价。
基本信息
| 全局标志 | 启用后查找不限于首个匹配,同时使正则对象带可推进的状态 |
|---|---|
| 粘性标志 | 从当前位置精确匹配、不向前搜索,同样会推进状态 |
| 多行与点号 | 多行让行首行尾按行生效,点号匹配换行让点号也吃掉换行符 |
| 字符处理 | Unicode 模式按码点处理并启用属性转义;另一种集合模式与它互斥 |
| 区间标志 | 提供匹配起止下标,包含命名分组的下标信息 |
典型使用场景
- 批量替换:需要替换全部出现位置时必须启用全局标志,否则只改第一处
- 词法与标记解析:按顺序从当前位置精确吃掉记号时使用粘性标志
- 跨行文本:处理多行配置时让锚点按行生效,避免整段只匹配一次
- 跨行块匹配:需要让点号跨越换行时启用点号匹配换行,注意贪心范围
- Unicode 文本:处理表情与扩展区字符时启用 Unicode 模式,否则按码元切分
- 位置相关处理:需要高亮或截取时使用区间标记获取下标
标志位用例
标志位用例
/error/gi.test('Error error'); // 全局加忽略大小写:两个都能命中
/a/g.exec('aa'); /a/g.exec('aa'); // 同一对象两次调用位置不同:全局状态会推进
/\d/y.exec('12'); // 粘性:从当前位置精确匹配,不向前搜索
/^a/m.test('b\na'); // 多行模式下锚点按行生效
/./s.test('\n'); // 点号匹配换行后为真
/\p{Script=Han}/u.test('中'); // Unicode 模式下可用属性转义
/a/d.exec('a').indices; // 取得匹配区间下标
// 标志重复或互斥会直接报错
// new RegExp('a', 'gg') 与同时使用两种字符模式都会抛语法错误标志与作用
| 标志 | 作用 | 常见误解 |
|---|---|---|
| g | 查找全部匹配并维护状态 | 以为只影响 replace 的替换次数 |
| i | 忽略大小写 | 以为在所有语言下折叠规则都相同 |
| m | 锚点按行生效 | 以为影响点号是否匹配换行 |
| s | 点号匹配换行 | 以为也能让字符类跨行 |
| u | 按码点处理并启用属性转义 | 以为能改变简写类的 ASCII 范围 |
| y | 粘性匹配,状态会推进 | 与全局标志混为一谈 |
| d | 提供匹配区间下标 | 忽略运行时兼容性 |
带全局或粘性标志的正则对象是有状态的:同一对象被多处共享时,上一次匹配的结束位置会成为下一次的起点,这是「同一段代码单独跑正常、组合起来就漏匹配」的典型原因。
两种按码点处理的标志互斥,且启用后对转义与字符类的解释更严格:一些在宽松模式下被当作字面量的写法会直接报错,启用前先跑一遍既有模式的回归。