有时我们需要找到仅满足以下条件的模式匹配:该模式后面或前面跟着另一个模式。
有一种特殊的语法用于此,称为“前瞻”和“后顾”,统称为“环顾”。
首先,让我们从类似 1 turkey costs 30€ 的字符串中找到价格。即:一个数字,后面跟着 € 符号。
前瞻
语法为:X(?=Y),表示“查找 X,但仅在后面跟着 Y 时匹配”。X 和 Y 可以是任何模式。
对于一个整数后面跟着€,正则表达式将是\d+(?=€)
let str = "1 turkey costs 30€";
alert( str.match(/\d+(?=€)/) ); // 30, the number 1 is ignored, as it's not followed by €请注意:前瞻仅仅是一个测试,括号(?=...)的内容不包含在结果30中。
当我们查找X(?=Y)时,正则表达式引擎会找到X,然后检查它后面是否紧跟着Y。如果不是,则跳过潜在的匹配,并继续搜索。
更复杂的测试是可能的,例如X(?=Y)(?=Z)意味着
- 查找X。
- 检查Y是否紧跟在X之后(如果不是,则跳过)。
- 检查Z是否也紧跟在X之后(如果不是,则跳过)。
- 如果两个测试都通过了,那么X就是一个匹配,否则继续搜索。
换句话说,这种模式意味着我们正在寻找X,后面紧跟着Y和Z。
只有当模式Y和Z不是相互排斥的时候才有可能。
例如,\d+(?=\s)(?=.*30)查找\d+,后面跟着一个空格(?=\s),并且在它之后某个地方有30(?=.*30)
let str = "1 turkey costs 30€";
alert( str.match(/\d+(?=\s)(?=.*30)/) ); // 1在我们的字符串中,它完全匹配数字1。
负向先行断言
假设我们想要一个数量,而不是来自同一个字符串的价格。这是一个数字\d+,后面不跟着€。
为此,可以应用负向先行断言。
语法是:X(?!Y),它表示“搜索X,但只有在后面不跟着Y的情况下”。
let str = "2 turkeys cost 60€";
alert( str.match(/\d+\b(?!€)/g) ); // 2 (the price is not matched)后行断言
请注意:后行断言在非 V8 浏览器(如 Safari、Internet Explorer)中不受支持。
先行断言允许为“后面是什么”添加条件。
后行断言类似,但它向后看。也就是说,它允许仅在它前面有某些内容的情况下匹配模式。
语法是
- 正向后查找:(?<=Y)X,匹配X,但仅当它之前有Y。
- 负向后查找:(?<!Y)X,匹配X,但仅当它之前没有Y。
例如,让我们将价格更改为美元。美元符号通常在数字之前,因此要查找$30,我们将使用(?<=\$)\d+ - 一个以$开头的金额。
let str = "1 turkey costs $30";
// the dollar sign is escaped \$
alert( str.match(/(?<=\$)\d+/) ); // 30 (skipped the sole number)并且,如果我们需要数量 - 一个数字,而不是以$开头,那么我们可以使用负向后查找(?<!\$)\d+
let str = "2 turkeys cost $60";
alert( str.match(/(?<!\$)\b\d+/g) ); // 2 (the price is not matched)捕获组
通常,后视括号内的内容不会成为结果的一部分。
例如,在模式\d+(?=€)中,€符号不会作为匹配的一部分被捕获。这是自然的:我们寻找一个数字\d+,而(?=€)只是一个测试,它应该以€结尾。
但在某些情况下,我们可能还想捕获后视表达式,或其一部分。这是可能的。只需将该部分包装在额外的括号中。
在下面的示例中,货币符号(€|kr)与金额一起被捕获
let str = "1 turkey costs 30€";
let regexp = /\d+(?=(€|kr))/; // extra parentheses around €|kr
alert( str.match(regexp) ); // 30, €以下是后视的相同情况
let str = "1 turkey costs $30";
let regexp = /(?<=(\$|£))\d+/;
alert( str.match(regexp) ); // 30, $总结
前瞻和后视(通常称为“后视”)在我们希望根据它之前/之后的上下文匹配某些内容时很有用。
对于简单的正则表达式,我们可以手动执行类似的操作。也就是说:匹配任何上下文中的所有内容,然后在循环中按上下文过滤。
请记住,str.match(没有标志g)和str.matchAll(始终)将匹配项作为带有index属性的数组返回,因此我们知道它在文本中的确切位置,并且可以检查上下文。
但总的来说,后视更方便。
后视类型
| 模式 | 类型 | 匹配 | 
|---|---|---|
| X(?=Y) | 正向前瞻 | X如果后面跟着Y | 
| X(?!Y) | 负向先行断言 | X如果后面不跟着Y | 
| (?<=Y)X | 正向后视 | X如果在Y之后 | 
| (?<!Y)X | 负向后视 | X如果不在Y之后 | 
评论
<code>标签,对于多行代码,请将其包装在<pre>标签中,对于超过 10 行的代码,请使用沙箱 (plnkr,jsbin,codepen…)