环视的四种类型

环视结构不匹配任何字符,只匹配文本中的特定位置。也称为零宽度断言。

类型正则表达式匹配成功的条件匹配方向
肯定顺序环视(?=…)子表达式匹配右侧文本从左到右
否定顺序环视(?!…)子表达式不能匹配右侧文本从左到右
肯定逆序环视(?<=…)子表达式匹配左侧文本从右到左
否定逆序环视(?<!…)子表达式不能匹配左侧文本从右到左

以下是 Chrome(版本 99.0.4844.51)控制台的调试结果,其中否定逆序环视的支持还不完善。

1
2
3
4
5
6
let str = "77abc88";

str.replace(/(?=abc)/g, "#"); // '77#abc88'
str.replace(/(?!7)/, "#"); // '77#abc88'
str.replace(/(?<=abc)/g, "#"); // '77abc#88'
str.replace(/(?<!7)/, "#"); // '#77abc88'

非捕获括号与捕获括号

1
2
3
4
5
let str = "abc abaa bb";
str.match(/(?:ab)+/g); // ['ab', 'ab']

str.replace(/(?:ab)+/g, "$1,"); // '$1,c $1,aa bb'
str.replace(/(ab)+/g, "$1,"); // 'ab,c ab,aa bb'

可以从例子看出,(?:ab)并没有捕获并赋值给$1(ab)有捕获并赋值给$1

实战

给数字字符串加入千分位分隔符,比如 123,456,0

1
2
3
let str = "1234560";

str.replace(/(\d)(?=(?:\d{3})+$)/g, "$1,");

解答过程如下:

  • 非捕获括号匹配连续的3个数字(?:\d{3})
  • 捕获括号匹配连续3个数字前的单个数字: (\d)(?:\d{3})
  • 加入环视:(\d)(?=(?:\d{3})+$),其中+$的含义是,n 组连续 3 个数字结尾的字符串
  • 替换:$1,