我正在构建一个PHP正则表达式,用于具有以下约束的用户名验证:
-长度必须为10-16个字符,包含字母、数字和至少一个特殊字符(*&^-_$)-不能以数字或特殊字符开头
更正:最后六位数字必须是月份/日期生日(MMYYYY format
)。为了进一步验证用户名,月份/日期必须显示用户名超过18,否则用户名将不会验证。提前感谢您的帮助!我已经被这个问题困扰了一段时间。
解决方案
您可以使用以下正则表达式来完成此操作:
/(?=^.{10,16}$)(?=.+?[*&^_$-])[a-z].+?[01]'d{3}$/i
这是一个带有一些单元测试的演示。
解释
/
分隔符(?=^.{10,16}$)
确保有10-16个字符,从开始到结束(?=
启动前瞻组- 字符串的
^
开头 .{10,16}
10到16个字符- 字符串的
$
结尾 )
结束前瞻组
(?=.+?[*&^_$-])
确保集合*&^_$-
中至少有一个特殊字符,并且它不是第一个(?=
启动前瞻组.+?
一个或多个字符,非贪婪[*&^_$-]
集合*&^_$-
中的任何字符(注意顺序;必须将-
放在第一位或最后一位,或者将其转义为'-
))
结束前瞻组
[a-z]
以字母开头.+?
以非贪婪的方式匹配任何字符,并根据需要进行回馈[01]'d{3}
匹配0
或1
,然后再匹配3位$
匹配字符串末尾/
结束分隔符i
使匹配不区分大小写
Regex构造的若干注记
请注意,有多种有效的方法可以做到这一点。为了纯粹的效率,可以在一定程度上简化上面的解决方案,为处理器省去一些步骤。
但为了可读性,我喜欢使用上面的内容。每个块、字符集或组的作用都很清楚,这使得它可读且可维护。
像/^[a-z](?=.*?[*&^_$-])[a-z0-9*&^_$-]{5,11}[01]'d{3}$
这样的东西很难阅读和理解。如果你想允许一个17个字符的用户名怎么办?你必须做一堆数学运算来确定你应该把{5,11}
改成{5,12}
。或者,如果您决定允许使用字符#
,则必须在两个位置添加它(顺便说一句,这意味着regex已经违反了DRY原则)。
奖金:为什么你的尝试失败
你在评论中说你尝试过这个:
(?=^.{10,16}$)^[a-z]['d]*[_$^&*]?[a-z0-9]+
第一部分(?=^.{10,16}$)
很好。^[a-z]
也是如此。
但['d]*
仅匹配零位或多位数字;它与字母或特殊字符不匹配。因此,例如,a&a...
将失败。
并且[_$^&*]?
只匹配零个或一个特殊字符。它将允许一个没有特殊字符的用户名通过,但会让一个有2个特殊字符的用户名失败。
[a-z0-9]+
只匹配这些字符,并且您省略了最后四个字符必须是数字要求。
您可能会发现regex101.com上对regex的解释很有帮助。(注意:我与该网站没有任何关系。)
您可以使用以下正则表达式:
^[a-zA-Z](?=.*[*&^_$-])['w*&^$-]{5,11}[01]'d{3}$
Regex分解:
^ # Line start
[a-zA-Z] # # match an alhpabet
(?=.*[*&^_$-]) # lookahead to ensure there is at least one special char
['w*&^$-]{5,11} # match 5 to 11 of allowed chars
[01]'d{3} # match digits 0/1 followed by 3 digits
$ # Line end
我使用了量词{5,11}
,因为一个字符在开始时匹配,而4个字符在结束时匹配,因此从所需的{10,16}
长度中取出了5个位置。