某些情况下,我们需要找在某些字符后面或前面的字符,在正则表达式中,他们叫做 “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 后面紧跟着 YX(?!Y)
:X 后面没有紧跟着 Y(?<=Y)X
:X 的前面最近的字符是 Y(?!<Y)X
:X 的前面最近的字符不是 Y