正则表达式
需求
校验Account,要求:账号以字母开头,由小写英文字母和数字组成的4-16位字符。
不知道怎么判断“由小写英文字母和数字组成”,(/^[0-9a-z]+$/
不行,因为纯小写字母或数字也能通过。
解决
策略:Require both letters and numbers - regExp
Look Ahead
Look Ahead 指形如(?=)
的正则。
Look Ahead:利用先行断言,当使用了这种技术后,可以有多个并列的正则如(?=)()
,先校验第一个正则,Look Ahead的作用是,它不占据空间,到第二个正则时还可以从同样的位置开始校验。
参考这里的第二篇回答:Regex lookahead, lookbehind and atomic groups
.*?
一般情况下,.表示任意字符,*表示{0, },?表示{0,1}。
需要注意,?
一般采取贪婪模式,即匹配尽可能多的字符(这些匹配上的字符的空间就被占据了)
由mdn:
如果紧跟在任何量词 *、 +、? 或 {} 的后面,将会使量词变为非贪婪(匹配尽量少的字符)
所以.*?
的意思是:甭管这里有什么字符,都匹配0次。
光看这些可能还是无法理解其必要性,我们看看解决策略里的写法:/^(?=.*?\d)(?=.*?[a-zA-Z])[a-zA-Z\d]+$/
首先最前面有^
,说明从头开始匹配,关注第一个Look Ahead,它的作用是从头开始检查,保证至少有一个数字。
如果直接写成(?=\d)
,开头有小写字母就会失效,不可行。
如果写成(?=.*\d)
,由于量词的贪心匹配原则,.*会把所有数字匹配走,而\d匹配不上。
所以既要兼顾开头是字母的情况,又要破坏贪心匹配原则,使用.*?
。
成功实践
根据实践,我上边对.*?的必要性解释是错的,其实没有?也可以。
1 | ^(?=.*[a-z])(?=.*\d)[a-z]{1}[a-z\d]{3,15}$ |
参考
评论