零宽断言(lookaround/zero-width assersion)是正则表达式中非常常用的特性,但是因为其一些带误导性的中文翻译和易于混淆的写法,让我一度每次使用都要先查文档。
一.写在前面
这篇文章讲的东西非常基础,之所以要写一遍完全是因为我智商经常离线,老把它们写混。如果你对下面五种模式及其用途了然于心,请不要浪费时间读这篇文章。
(?:pattern)
非捕获匹配(matches pattern but does not capture the match)(?=pattern)
零宽正向先行断言(lookahead)(?!pattern)
零宽负向先行断言(negative lookahead)(?<=pattern)
零宽正回顾后发断言(lookbehind)(?<!pattern)
零宽负回顾后发断言(negative lookbehind)
之所以我要在每种模式后打出它的英文表达方式,不是为了装B,而是想让大家感受一下这个翻译(msdn,javascript权威指南等多本书籍或文档采用这样,或者类似这样的翻译)。我反正是第一次体会到英文看的明明白白,中文看得一头雾水的感觉。
二.功能介绍
相比理解这些模式的中文名,理解它们的用法要简单得多。(更多详情可以参见文章最后的测试用例)
(?:a)(b)\\1
匹配abb,如果是(a)(b)\\1
则匹配aba,(?:pattern)
表示匹配但不捕获,可以将其理解成不创建分组的(pattern)
。a(?=b)
断言a后面有b,匹配ab但不匹配aa,最终捕获a。(个人认为应该翻译成正向肯定查找)a(?!b)
断言a后面没有b,匹配aa但不匹配ab,最终捕获a。(个人认为应该翻译成正向否定查找)(?<=a)b
断言b前面有a,匹配ab但不匹配bb,最终捕获b。(个人认为应该翻译成反向肯定查找)(?<!a)b
断言b前面没有a,匹配bb但不匹配ab,最终捕获b。(个人认为应该翻译成反向否定查找)
三.Polyfill
lookbehind目前还处在es7的提案阶段,因此无法在js中直接使用(也正因为如此,VSC的查找与替换不支持lookbehind),新版的V8引擎已经实现了该功能。不过需要在浏览器设置中打开“#enable-javascript-harmony”开关(在chrome地址栏输入about:flags设置)
在js实现该功能之前,可以使用捕获与引用来达成类似的效果,举例来说如果你需要将所有前面带有static修饰符的int,替换成long,在支持lookbehind的编辑器中可以直接查找(?<=static\s)int
,并将其替换成long
。而在不支持lookbehind的环境下(vscode别瞅了,说的就是你!),可以查找(static\s)int
,将其替换成$1long
。
四.Code Demo
Polyfill Demo(js)
Feature Demo(java)