在我的正则表达式中,我试图匹配8到16个字符之间的密码,其中至少有2个符合以下条件:小写字母,大写字母和数字。
在我的表达中,我有:
^((?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,16})$
但我不明白为什么它不会这样:
^((?=\d)(?=[a-z])(?=[A-Z])(?=\d)(?=[a-z])(?=[A-Z]){8,16})$
不“。*”只是意味着“零或更多的任何角色”?那么,如果我只是检查具体情况,为什么还需要呢?
为什么我需要在大括号定义密码限制之前的时间段?
还有一件事,我不明白“不消耗任何字符串”对“?=”的含义是什么意思。
答案 0 :(得分:2)
您的最后两个问题是相关的。 ?=
(顺便称之为前瞻)不会消耗任何字符串,这意味着它会测试字符串的条件但它本身是零字符长。如果前瞻为真,则匹配继续,但表达式的下一部分从检查前瞻之前的位置开始。
因为你的所有东西都是由前瞻组成的,所以它们的长度都是零。因此,要使{8,16}
匹配某些内容,您需要先提供.
。 .{8,16}
表示“8到16个字符,我不在乎这些字符是什么。” {8,16}
之前没有任何内容的.{8,16}
不是一个有效的表达式(或者至少不代表.*
的意思)。
关于您的第一个问题,每个前瞻中都需要^
,因为您的表达式以.*
开头。这意味着“从字符串的最开头”开始,而不是“匹配字符串中的任何位置”。由于您不是仅尝试在字符串的开头匹配,^((?=.*\d.*\d)(?=.*[a-z].*[a-z])(?=.*[A-Z].*[A-Z]).{8,16})$
允许您使前瞻符影响字符串中的任何位置。
最后,我担心你的正则表达式不起作用。因为前瞻是零长度的,所以将你所做的两次相同的前瞻两次匹配相同的东西。因此,此表达式仅检查您是否具有要强制执行的每种类型字符的单个实例,并且存在两个实例。你想要的表达式更像是这样:
^((?=(.*\d){2})(?=(.*[a-z]){2})(?=(.*[A-Z]){2}).{8,16})$
那个表达式相当于更优雅:
{{1}}
(而且,在它到期的地方给予信任,丹尼斯打败了我最后的表达。干得好,先生。)
答案 1 :(得分:1)
问题是这个角色^
意味着“正确的开始”。这意味着这些特定字符应该严格地位于您正在搜索的文本的开头,这不是您想要的。
答案 2 :(得分:1)
你的表达不会按你的意愿运作。
由于前瞻,(?=.*\d)
的两个实例实际上都匹配相同的数字,因此只用一位数验证密码。
这应该有效:
^(?=(.*\d){2})(?=(.*[a-z]){2})(?=(.*[A-Z]){2}).{8,16}$
答案 3 :(得分:1)
(?=.*\d)
和(?=\d)
之间的区别在于,虽然它们都是零宽度前瞻,但如果字符串中的任何位置(在当前位置之后),前者将匹配,但后者仅在该数字紧跟在当前位置之后才匹配。因此,第一个正则表达式查找8-16个字符,包括一个数字,小写和大写。第二个正则表达式要求第一个字符是数字,小写和大写,这是荒谬的。如果您想要计算两位数,而不是(?=.*\d)(?=.*\d)
,请执行(?=.*\d.*\d)
。