正则表达式 Lookahead、LookBehind

 

某些情况下,我们需要找在某些字符后面或前面的字符,在正则表达式中,他们叫做 “lookaroud”。

题目(下文有引用):

1 turkey costs 30€

lookahead

Lookahead,即查找某个字符 A,但是字符 A 后紧跟着的其他字符必须匹配特定规则。

它的语法为:


它的意思是:查找 ```X```,但是他的后面必须**立即**跟随着 ```Y```,```X``` 和 ```Y``` 可以是任意字符。

使用 lookahead 来实现上面的题目的功能:找到在 € 字符前面的数字,也就是 30。

即查找某个以欧元结尾的数字,它的正则表达式为:

```\d+(?=€)```

**注意:**lookahead 仅仅是测试是否符合条件,不管是否符合条件,括号内的匹配规则 (?=€) 都不会包含在结果中,⬇️

```javascript
let str = "1 turkey costs 30€";

alert( str.match(/\d+(?=€)/) ); // 30

// 数字 1 会忽略掉,因为它后面没有 € 字符

在查找的过程中,正则表达式会搜索 X,检查 X 的后面是否有 Y 字符。如果没有,那么 X 这个潜在的匹配结果会被忽略掉,然后继续下一次搜索。

同样可以添加更复杂的表达式,例如:


它的意思是:

1. 查找 X ;
2. 检查 X 后面紧跟着的是否是 Y 这个字符(如果不是则退过此次查找);
3. 检查 X 后面紧跟着的是否是 Z 这个字符(如果不是则退出此次查找);
4. 如果上述检查都通过,则 X 这个字符符合查找规则。

也就是说,当 Y 和 Z 互相不互斥的时候才能匹配。

例如:```\d+(?=\s)(?=.*30)``` 查找 ```\d+```,后面紧跟着一个空格 ```(?=\s)```,然后后面某个地方有 30 这个字符 ```(?=.*30)```:

```javascript
let str = "1 trukey costs 30€";

alert( str.match(/\d+(?=\s)(?=.*30)/) ); // 1

Negative lookahead

Negative lookahead 即对 lookahead 进行取反匹配,语法是 (?!Y),Y 是任意字符

假如还是上面那个题目,我们想找某个数字,后面没有被 € 符号跟随:

let str = "2 turkeys cost 60€";

alert( str.match(/\d+\b(?!)/g ); // 2
// 后面跟随 € 的 60 没有匹配到

Lookbehind

Lookbehind 的查找方向和 Lookahead 相反。

Lookbehind 即查找某个字符 A,但是字符 A 前紧跟着的其他字符必须匹配特定规则。

它的语法为:(?<=Y)X,当 X 前面紧跟着 Y,则符合匹配。

它同样也有消极匹配:(?<!Y)X,当 X 前面没有紧跟着 Y,则符合匹配。

例如:假设上面那道题目的价格单元为美元符号 $,$ 符号一般在数字的前面,所以如果要查找 $30,应使用正则表达式:(?<=\$)\d+

let str = "1 turkey costs $30";

// $ 需要转义成 \$
// 单独的 1 被省略
alert( str.match(/(?<=\$)\d+/) ); // 30

假设我们需要某个数字,前面没有跟随 $ 符号,那我们可以使用 negative lookbehind (?<!\$)\d+

let str = "2 trukeys cost $60";

// $60 被省略
alert( str.match(/(?<!\$)\b\d+/g) ) // 2

Capturing groups

通常情况下,在 “lookaround” 括号内的内容不会成为正则表达式匹配结果的一部分。

例如:正则表达式 \d+(?=€),欧元符号 € 不会成为匹配结果的一部分,这也是合理的,因为我们查找某个数字 \d+,而不需要返回后面的 (?=€) 这一部分,因为我们仅仅在搜索时需要用它来做匹配。

但是某些情况下,我们可能需要在返回的结果中获取到这一部分,那可以在它的外面再额外包一层括号 ()。

下面例子中,匹配的结果中会返回币种符号:

let str = "1 trukey costs 30€";

// 额外再包一层括号
let regexp = /\d+(?=(€|kr))/;

alert( str.match(regexp) ) // 30, €

同样也适用于 lookbehind:

let str = "1 trukey costs $30";
let regexp = /(?<=(\$))\d+/;

alert( str.match(regexp) ); // 30, $

总结

lookahead 和 lookbehind,统称 lookaround;

它的应用场景是:在我们需要查找某个字符 A,它的前面或者后面必须紧跟着某个字符。

Lookaround 类型:

  • X(?=Y): X 后面紧跟着 Y
  • X(?!Y):X 后面没有紧跟着 Y
  • (?<=Y)X:X 的前面最近的字符是 Y
  • (?!<Y)X:X 的前面最近的字符不是 Y