Skip to content
目录

前瞻断言与后瞻断言

有时候我们需要匹配后面跟着特定模式的一段模式。比如,我们要从 subject:1 turkey costs 30€ 这段字符中匹配价格数值。

我们需要获取 subject:€ 符号前面的数值(假设价格是整数)。

那就是前瞻断言要做的事情。

前瞻断言

语法为:pattern:x(?=y),它表示“仅在后面是 pattern:y 的情况匹配 pattern:x”。

那么对于一个后面跟着 的整数金额,它的正则表达式应该为:pattern:\d+(?=€)

let str = "1 turkey costs 30€";

alert( str.match(/\d+(?=)/) ); // 30 (正确地跳过了单个的数字 1)
1
2
3

让我们来看另一种情况:这次我们想要一个数量,它是一个不被 subject:€ 跟着的数值。

这里就要用到前瞻否定断言了。

语法为:pattern:x(?!y),意思是 "查找 pattern:x, 但是仅在不被 pattern:y 跟随的情况下匹配成功"。

let str = "2 turkeys cost 60€";

alert( str.match(/\d+(?!)/) ); // 2(正确地跳过了价格)
1
2
3

后瞻断言

前瞻断言允许添加一个“后面要跟着什么”的条件判断。

后瞻断言也是类似的,只不过它是在相反的方向上进行条件判断。也就是说,它只允许匹配前面有特定字符串的模式。

语法为:

  • 后瞻肯定断言:pattern:(?<=y)x, 匹配 pattern:x, 仅在前面是 pattern:y 的情况。
  • 后瞻否定断言:pattern:(?<!y)x, 匹配 pattern:x, 仅在前面不是 pattern:y 的情况。

举个例子,让我们把价格换成美元。美元符号通常在数字之前,所以要查找 $30 我们将使用 pattern:(?<=\$)\d+ —— 一个前面带 subject:$ 的数值:

let str = "1 turkey costs $30";

alert( str.match(/(?<=\$)\d+/) ); // 30 (跳过了单个的数字 1)
1
2
3

另外,为了找到数量 —— 一个前面不带 subject:$ 的数字,我们可以使用否定后瞻断言:pattern:(?<!\$)\d+

let str = "2 turkeys cost $60";

alert( str.match(/(?<!\$)\d+/) ); // 2 (跳过了价格)
1
2
3

捕获组

一般来说,环视断言括号中(前瞻和后瞻的通用名称)的内容不会成为匹配到的一部分结果。

例如:在模式 pattern:\d+(?!€) 中,pattern:€ 符号就不会出现在匹配结果中。

但是如果我们想要捕捉整个环视表达式或其中的一部分,那也是有可能的。只需要将其包裹在另加的括号中。

例如,这里货币符号 pattern:(€|kr) 和金额一起被捕获了:

let str = "1 turkey costs 30€";
let reg = /\d+(?=(|kr))/; // €|kr 两边有额外的括号

alert( str.match(reg) ); // 30, €
1
2
3
4

后瞻断言也一样:

let str = "1 turkey costs $30";
let reg = /(?<=(\$|£))\d+/;

alert( str.match(reg) ); // 30, $
1
2
3
4

总结

当我们想根据前面/后面的上下文筛选出一些东西的时候,前瞻断言和后瞻断言(通常被称为“环视断言”)对于简单的正则表达式就很有用。

有时我们可以手动处理来得到相同的结果,即:匹配所有,然后在循环中按上下文进行筛选。请记住,str.matchAllreg.exec 返回的匹配结果有 .index 属性,因此我们能知道它在文本中的确切位置。但通常正则表达式可以做得更好。

环视断言类型:

模式类型匹配
pattern:x(?=y)前瞻肯定断言x ,仅当后面跟着 y
pattern:x(?!y)前瞻否定断言x ,仅当后面不跟 y
pattern:(?<=y)x后瞻肯定断言x ,仅当跟在 y 后面
pattern:(?<!y)x后瞻否定断言x ,仅当不跟在 y 后面

前瞻断言也可用于禁用回溯。为什么它是需要的 - 请看下一章。

前瞻断言与后瞻断言 has loaded