ES2018 新特性
“正则表达式反向断言” 提案 proposal-regexp-lookbehind 由 Gorkem Yakin, Nozomu Katō, Daniel Ehrenberg 负责,目前已经进入 stage 4,预计会是 ES9(ES2018) 的一部分。
1. 概述
断言(Assertion)是一个对当前匹配位置之前或之后的字符的测试, 它不会实际消耗任何字符,所以断言也被称为“非消耗性匹配”或“非获取匹配”。
正则表达式的断言一共有 4 种形式:
零宽正向肯定断言(zero-width positive lookahead assertion)
零宽正向否定断言(zero-width negative lookahead assertion)
零宽反向肯定断言(zero-width positive lookbehind assertion)
零宽反向否定断言(zero-width negative lookbehind assertion)
这里面的 pattern 是一个正则表达式。
lookahead 和 lookbehind 通过被翻译为:
正向 负向
前向 后向
正向 反向
前瞻 后瞻
……
本文档使用“正向”、“反向”。
2. Lookahead assertions 正向断言
在当前的 JavaScript 正则表达式版本中,只支持正向断言。
正向断言的意思是:当前位置后面的字符串应该满足断言,但是并不捕获,仅此而已。
举个例子:
这个正则表达式可以匹配 ,但是正则表达式匹配到的字符串不包含 。(这个正则表达式可以匹配 中的 ,注意,匹配的结果是 ,并不是 )
但是如果这个字符串没有包含 ,那么这个正则表达式无法成功匹配:
如果使用否定断言则正好相反:
3. 反向断言
反向断言和正向断言的行为一样,只是方向相反。
反向肯定断言使用语法 。
比如我们想获取所有的人民币金额,但是不获取其它货币(比如美元):
反向否定断言使用语法 ,和肯定断言正好相反:
在上面的例子中, 的结果是 ,并不是我们认为的 。
这不是反向断言的一个例外,而是这段代码的一个小 bug。
这段正则表达式匹配到了 里面的 。因为 前面是 而不是 ,完全符合反向否定断言规则。
4. 组合
多个断言(任意顺序)可以同时出现。
比如 匹配前面有三个数字但不是 的字符串 。
注意,每个断言独立应用到对目标字符串该点的匹配。首先它会检查前面的三位都是数字,然后检查这三位不是 。 这个模式不能匹配 前面有三位数字然后紧跟 3 位非 共 6 个字符的字符串,比如, 它不匹配 。 匹配 这个字符串的模式可以是 。
这种情况下,第一个断言查看(当前匹配点)前面的 6 个字符,检查前三个是数字, 然后第二个断言检查(当前匹配点)前三个字符不是 。
断言可以以任意复杂度嵌套。
比如 匹配前面有 但是 前面没有 的 。
另外一个模式 则匹配前面有三个数字字符紧跟 3 个不是 的任意字符的 。
5. 细节
5.1 从右向左的贪婪匹配
如果组中有贪婪匹配的子模式,则在反向断言中的捕获组将具有不同的值。
当在反向断言中,右侧的组将捕获大多数字符,而不是左侧的组。
当模式 匹配 时,第 1 个组捕获 ,第 2 个组捕获 。
当普通模式 匹配 时,第 1 个组捕获 ,第 2 个组捕获 。
5.2 捕获组的索引
在反向断言匹配中,组的次序是从左到右的。
当模式 匹配 时, 是 , 是 。
5.3 引用捕获组
只有当捕获组被执行后,我们才能对他进行引用。
例如在正则表达式 中, 的值始终是空字符串,正确的写法是 。
6 实现
V8, shipping in Chrome 62
XS, in January 17, 2018 update
领取专属 10元无门槛券
私享最新 技术干货