在我的正则表达式中,我尝试匹配 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})$
“.*”不只是表示“零个或多个任意字符”吗?那么,如果我只是检查特定条件,为什么需要它呢?
为什么我需要在定义密码限制的大括号之前加上句点?
还有一件事,我不明白引用“?=”时“不消耗任何字符串”意味着什么。
最佳答案
您的最后两个问题是相关的。 ?=
(顺便说一句,这称为前瞻)不会消耗任何字符串,这意味着它测试字符串的条件,但其本身的长度为零字符。如果前瞻为真,则匹配继续,但表达式的下一部分从检查前瞻之前的位置开始。
因为您的所有内容都是由前瞻组成的,所以它们的长度加起来都为零。因此,要使 {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})$
(而且,丹尼斯在最后一个表达上比我更早地做出了应有的贡献。干得好,先生。)
关于javascript - 寻找另一个正则表达式解释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8275682/