需求

校验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
2
3
^(?=.*[a-z])(?=.*\d)[a-z]{1}[a-z\d]{3,15}$

// 注意{3,15}这里不能有空格!

参考

正则表达式-MDN

Regular-Expressions.info