如何构造用于用户名验证的正则表达式


How to construct a regex expression for username validation?

我正在构建一个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}匹配01,然后再匹配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个位置。