正则表达式的lookaround(lookahead/lookbehind)以及密码复杂度检查
前言
密码复杂度校验是很常见的功能,一般用正则实现。
网上搜索到的内容,使用了正则的Lookaround表达式,之前没有用过,这里记录一下
Lookaround
主要的内容来自这里,讲的很通俗易懂。这里做一下简单的翻译
Lookaround包括Lookahead和Lookbehind两种匹配模式。
功能解释
有时候我们需要匹配一段文本,但是只有当这段文本有特定的前缀 或者后缀时才匹配到他
比如1 turkey costs 30€,我们想获得这里的价格30,这个数字的特点是,他有一个后缀€
这时候就可以用Lookahead
Lookahead
Lookahead的语法是X(?=Y),它的意思是,查询X,但是仅当X的后面跟的是Y时
当然,这里的X和Y都可以是正则表达式的匹配模式
以前面的需求为例,需要查询一个有€后缀的数字,那么相应的正则表达式是\d+(?=€)。
let str = "1 turkey costs 30€";
alert( str.match(/\d+(?=€)/) ); //30
需要注意的是Lookahead语法匹配的后缀仅仅是检测使用,不会在返回结果(30)中
Lookahead还可以支持更复杂的场景,比如X(?=Y)(?=Z),它的含义是:
- 找到
X - 校验
Y是否紧跟X(否则丢弃) - 校验
Z是否紧跟X(否则丢弃) - 如果2和3都匹配,则
X匹配,否则继续搜索
这种情况下,Y和Z不能是互斥的
举个例子,\d+(?=\s)(?=.*30),这里查找一个数字,这个数字后面紧跟一个空格,并且在这个数字后面的某个地方,有一个数字30``(?=.*30):
let str = "1 turkey costs 30€";
alert( str.match(/\d+(?=\s)(?=.*30)/) ); // 1
Negative Lookahead
如果我们想找一个数字,他后面不是€符号呢?这时候可以用Negative Lookahead模式:X(?!Y)
它的意思是,寻找X,但是仅当X的后面不是Y的时候
let str = "2 turkeys cost 60€";
alert( str.match(/\d+\b(?!€)/g) ); // 2
Lookbehind
Lookahead检测的是后缀,而Lookbehind检测的是前缀。
和Lookahead类似,Lookbehind也有Positive、Negative两种匹配方式:
- Positive lookbehind:
(?<=Y)X, 仅当X前面是Y时匹配成功 - Negative lookbehind:
(?<!Y)X, 仅当X前面不是Y时匹配成功
还是用之前的例子,把单位换成人民币¥,这时候我们想要匹配¥30,需要使用(?<=¥)\d+,匹配一个前缀是¥的数字:
let str = "1 turkey costs ¥30";
alert( str.match(/(?<=¥)\d+/) ); // 30
如果想要匹配数量,即没有前缀的数字,而非价格,那么可以使用(?<!\$)\d+
捕获组(Capturing Group)
之前提到一点,无论是Lookaround还是Lookbehind,匹配的内容都不包含前缀和后缀本身。
比如对于这个模式\d+(?=€),€就不在最后的结果当中。
如果想要在结果中添加€,那么可以用括号把需要匹配的内容包括起来。
在下面这个例子里(€|kr)就会和价格的数字一起返回:
let str = "1 turkey costs 30€";
let regexp = /\d+(?=(€|kr))/; // €|kr周围加了括号
alert( str.match(regexp) ); // 30, €+
关于密码复杂度验证
回到最开始的目的,密码复杂度校验。要求是8~20位,包含字母、数字和特殊字符。
网上很容易搜到解决方案:^(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[._~!@#$^&*])[A-Za-z0-9._~!@#$^&*]{8,20}$
整个表达式可以分为4部分
^(?=.*[a-zA-Z])^(?=.*[0-9])注意这里开头的^就是前面提到的级联的用法,虽然^不在这个表达式之前,但是匹配时也是这样检测的。^(?=.*[._~!@#$^&*])[A-Za-z0-9._~!@#$^&*]{8,20}
其中1-3分别用来匹配字母、数字、特殊字符,这里用到的是Lookahead后缀匹配,而匹配的内容是^既字符串的开头。
所以1-3确保了不同类型字符串存在,4确保了字符串数量正确。

浙公网安备 33010602011771号