
概述
续接上文的密码校验要求:
这个需求有两个难点,一,是如何使用正则匹配所有半角英文标点符号,二,是如何验证密码段中在要求的四种(大写字母,小写字母,数字,标点符号)类型中至少存在三种。
第一个难点:如何使用正则匹配所有半角英文标点符号在上文中已经得以解决,所以在这里我们主攻第二个难点并完成完整的符合需求的表达式。
太长不看版
满足需求:完全符合上述图片的校验需求,密码段中在要求的四种(大写字母,小写字母,数字,标点符号)类型中至少存在三种
解决方案:灵活运用正则中的零宽度负先行断言:
^(?!^[0-9a-z]+$)(?!^[0-9A-Z]+$)(?!^[0-9\x21-\x2f\x3a-\x40\x5b-\x60\x7B-\x7F]+$)(?!^[a-zA-Z]+$)(?!^[a-z\x21-\x2f\x3a-\x40\x5b-\x60\x7B-\x7F]+$)(?!^[A-Z\x21-\x2f\x3a-\x40\x5b-\x60\x7B-\x7F]+$)(?!^[A-Z\x21-\x2f\x3a-\x40\x5b-\x60\x7B-\x7F]+$)[a-z0-9A-Z\x21-\x2f\x3a-\x40\x5b-\x60\x7B-\x7F]+$
能被匹配到的则满足上述图片需求
详细解释
零宽断言是正则表达式中的一种进阶使用方法,灵活运用零宽断言能让正则表达式变得更为简练,并且使其功能变得更为强大。
正则的零宽断言一般有以下四种:
借用司徒正美大大的解释
但可惜的是javascript并不支持(?<=exp)和(?<!exp)的用法。而我们这次使用的则是零宽度负先行断言
零宽度负先行断言原理解释:
(?!exp)这个断言的用法是:只有当字符串右侧不出现匹配exp的字符串时才匹配正则表达式。
我们先从一个简单的例子讲解:
如果我们要匹配一串字符,所有字符必须为小写字母或者数字,并且必须要有小写字母。
那么换一种思路,就是我们的字符串必须为小写字母或数字构成,并且不能为纯数字。
所以我们使用零宽度负先行断言,则可以写成
^(?!^[0-9]+$)[a-z0-9]+$
断言(?![1]+$)则表示纯数字的组合不能被匹配。
把例子加深一下:
我们要匹配一串字符,所有字符必须为小写字母或者数字,并且必须同时有小写字母和数字的存在。
那么换一种思路,就是我们的字符串必须为小写字母或数字构成,并且不能为纯数字或者是纯小写字母。
所以我们使用零宽度负先行断言,则可以写成
^(?!^[0-9]+$)(?!^[a-z]+$)[a-z0-9]+$
断言(?![0-9]+$)则表示纯数字的组合不能被匹配;断言(?![a-z]+$)则表示纯小写字母的组合不能被匹配。
二者相组合,就能够把所有纯数字和纯小写字母的组合给排除掉了,剩下的就是同时有小写字母和数字的组合。
怎么样,思路出来了吗?
把例子再次深化:
我们要匹配一串字符,所有字符必须为小写字母或者数字或者大写字母,并且必须至少有三种字符中的两种。
那么我们整理下思路,实际上就是我们的字符串必须为上述三种字符构成,并且不能为纯数字或纯小写字母或纯大写字母。
所以我们使用零宽度负先行断言,则可以写成
^(?!^[0-9]+$)(?!^[a-z]+$)(?!^[A-Z]+$)[a-z0-9A-Z]+$
这样做,就可以把纯数字(?![0-9]+$),纯小写字母(?![a-z]+$),纯大写字母(?![2]+$)统统排除了。
练级完成,是时候面对大BOSS了
在上一篇JS的JS正则密码复杂度校验文章中,我们知道了要匹配所有的半角表单符号的正则表达式是:
/[\x21-\x2f\x3a-\x40\x5b-\x60\x7B-\x7F]/
配合上面的断言语句,我们可以去单挑boss了:
验证密码段中在要求的四种(大写字母,小写字母,数字,标点符号)类型中至少存在三种,我们就可以将思路转换为:
在只有上述四种类型范围的字符串中,找出所有从头到尾只有两种以下字符的字符串并将它们排除就可以了。
那么根据排列组合,我们需要排出的就是
数字和小写字母(?![3]$),
数字和大写字母(?![4]$),
数字和符号(?![5]$),
小写字母和大写字母(?![6]$),
小写字母和符号(?![7]$)
还有大写字母和符号(?![8]$)
于是乎,最后的正则成品:
^(?!^[0-9a-z]+$)(?!^[0-9A-Z]+$)(?!^[0-9\x21-\x2f\x3a-\x40\x5b-\x60\x7B-\x7F]+$)(?!^[a-zA-Z]+$)(?!^[a-z\x21-\x2f\x3a-\x40\x5b-\x60\x7B-\x7F]+$)(?!^[A-Z\x21-\x2f\x3a-\x40\x5b-\x60\x7B-\x7F]+$)(?!^[A-Z\x21-\x2f\x3a-\x40\x5b-\x60\x7B-\x7F]+$)[a-z0-9A-Z\x21-\x2f\x3a-\x40\x5b-\x60\x7B-\x7F]+$
就能满足我们的需求
总结
正则表达式的学习入门比较容易,上手也不难。在面对一些很长的正则表达式或者看似奇葩的正则表达式匹配需求时,我们不妨静下心来,慢慢地去分析它们,找到个中规律之后,正则表达式的迷雾也就被揭开了。而正则表达式这把神器,也能被我们随心所欲地挥舞了。