当我们需要匹配一些字符,这些字符之前或者之后必须是特定内容的情况时,最明智的一种解决方案应该是零宽断言了。
定义
用于给指定位置添加限定条件(断言),在这个位置之前或者之后满足这个限定条件时,该断言成功。
当断言失败时不会再继续匹配,当断言匹配成功后正则表达式中的其他匹配才会继续。
断言部分也可以是一个正则表达式。
类型
- ?= 正向零宽匹配:匹配字符位置后的条件
简单举个例子:
let a = '123ab';
a.match(/\d+(?=ab)/)
//["123", index: 0, input: "123ab", groups: undefined]
复制代码
这个例子是匹配ab字符前面的数字,也就是需要匹配的字符后面需要满足等于ab的条件
- ?! 正向零宽不匹配:匹配字符位置后的条件的非
简单举个例子
let a = '132cd';
a.match(/\d+(?!ab)/)
//["132", index: 0, input: "132cd", groups: undefined]
复制代码
这个和上面那个的使用一致,但个人感觉取非不够精确,在正则里取非的范围有点大,所以感觉可能?=
更常用一下
举个例子,会出现下面这种情况
let a = '132ab';
a.match(/\d+(?!ab)/)
//["13", index: 0, input: "132ab", groups: undefined]
复制代码
- ?<= 负向零宽匹配:匹配字符位置前的条件
简单举个例子
let a = '132ab';
a.match(/(?<=\d)[a-z]+/)
//["ab", index: 3, input: "132ab", groups: undefined]
复制代码
这个例子是为了匹配紧跟数字后面的所有小写英文单词,也就是为了匹配一串小写英文字符串前面必须满足是数字的条件
- ?<! 负向零宽不匹配:匹配字符位置前的条件的非
这个与前面的第二种类似,不过是负向的,也就是字符前面应满足断言部分正则表达式,感觉也应该不常用,这里不细写了
组合使用
正向零宽和负向零宽的组合使用,可以简化一些特定的匹配 先举个简单的例子 比如我需要匹配英文字母间的数字
let a = 'qee132ab';
a.match(/(?<=[a-z]+)\d+(?=[a-z]+)/)
//["132", index: 3, input: "qee132ab", groups: undefined]
复制代码
比如我要上面的匹配全局使用
a = 'qee132ab324asd';
a.match(/((?<=[a-z]+)\d+(?=[a-z]+))/g)
//["132", "324"]
复制代码
之前做了一道题,用于匹配字符中变量x的值(比如字符串为‘x=5’,匹配的结果则为5,‘fox=5’,匹配的结果则为null)
这样的匹配使用零宽匹配可以节省很多事
a = 'fox x=5 fox';
a.match(/(?<=\bx=)\d+(?!\d+)/g)
//["5"]
复制代码
总结
零宽断言主要有两个点:
- 零宽断言标示后面可以跟一个正则匹配方程式
如上面的例子,(?<=\bx=)
零宽标示?<=
后面的是一个正则表达式\bx=
,当然也可以是其他的任何正则表达式
- 零宽匹配完成后匹配的位置仍为当前位置
举个例子
a = '123qwe';
a.match(/(?=\d+)\d+[a-z]+/g)
//["123qwe"]
复制代码
因为零宽匹配后,匹配的位置不变,零宽匹配了第0个位置,第0个位置的后面是数字,所以(?=\d+)
匹配成功,值为'',这个时候后面仍需要匹配,因为零宽匹配不移动位置,仍从第0个位置开始,这个时候需要匹配\d+[a-z]+
,这个匹配表达式匹配到了123qwe
,所以整个表达式匹配到的值为123qwe