正则表达式(Regex)用于密码验证

3
以下是符合以下密码标准的正确“正则表达式”:
至少包含1个小写字母。 必须包含至少1个大写字母。 必须包含至少1个数字。 必须包含至少1个特殊字符(只允许使用以下特殊字符:! #%)。 不能包括除A-Za-z0-9!#%之外的任何其他字符(例如,不能包括;)。 长度必须在8到32个字符之间。
这是我尝试过的,但不起作用:
^(?=.*?[a-z])(?=.*?[A-Z])(?=.*?[0-9])(?=.*?[\!\#\@\$\%\&\/\(\)\=\?\*\-\+\-\_\.\:\;\,\]\[\{\}\^]).{8,32}

但应该是:

但它应该是:

^(?=.*?[a-z])(?=.*?[A-Z])(?=.*?[0-9])(?=.*?[\!\#\@\$\%\&\/\(\)\=\?\*\-\+\-\_\.\:\;\,\]\[\{\}\^])[A-Za-z0-9!#%]{8,32}

但是无论如何,Unihedron的解决方案更好,只是想为将来阅读这个问题的用户提供一些信息。 :)

Unihedron的解决方案(也可以在他下面的答案中找到,我复制了它给自己,以防他在答案中进行更新并提供更好的版本):

^(?=[^a-z]*[a-z])(?=[^A-Z]*[A-Z])(?=\D*\d)(?=.*?[!#%])[A-Za-z0-9!#%]{8,32}$

我得到了以下的正则表达式:regex
^(?=[^a-z]*[a-z])(?=[^A-Z]*[A-Z])(?=\D*\d)(?=.*?[\!\#\@\$\%\&\/\(\)\=\?\*\-\+\-\_\.\:\;\,\]\[\{\}\^])[A-Za-z0-9\!\#\@\$\%\&\/\(\)\=\?\*\-\+\-\_\.\:\;\,\]\[\{\}\^]{8,60}$

再次感谢Unihedron和skamazin。非常感谢!


1
顺便说一句,你不必担心帖子的更改,当它们被编辑时,你总是可以查看帖子的修订版本 - Unihedron
1
我不太了解PHP,但你可以这样做。使用ToLower()将字符串转换为小写并与原始字符串进行比较,使用ToUpper()并进行比较。将(0-9)替换为''并进行比较等。由于长度非常短,您根本不必担心运行时间。在我看来,这比正则表达式更易读。不知道它是否更快。 - Steve
@Steve 我会进行一些实验,完成后会发布性能结果。只希望我不会忘记在这里发布它们。:/ - Jo Smo
1
@Steve 可读性好的代码?[不不不,千万别……] (https://www.thc.org/root/phun/unmaintain.html) - Unihedron
@Unihedron 我认为现在的计算机/服务器更好,所以我猜除非非常紧急,否则出于可维护性的考虑,最好使用 regex 方法。如果我有对“疯狂性能”的需求或者如果情况极其紧急,那么我会欣赏 Steve 的方法(这就是为什么我也点赞了 Steve 的想法)。很高兴知道您有多种选择。再次感谢! :) - Jo Smo
显示剩余8条评论
2个回答

8

@Unihedron,星号 * 是用来做什么的? - Jo Smo
1
@tastro 星号是“从零到一”的量词。在正则表达式中使用它们,可以通过跳过无关字符(无需回溯)来实现高效匹配。另请参阅Stack Overflow Regex Reference - Unihedron
1
@Unihedron,你能帮我澄清一下吗:使用(?=[^a-z]*[a-z])比使用(?=.*[a-z])更快(正则表达式引擎所需的步骤数),因为后者需要回溯直到匹配成功,对吗?第一个不需要回溯,因为[^a-z]*会在第一个字母字符处停止,然后[a-z]会匹配该字母字符,对吗? - skamazin
2
@skamazin 是的,这是正确的。这种技术可以通过正则表达式引擎的工作方式来解释 - 有两个指针,一个在模式上,另一个在字符串上。指针尽可能地执行,因此最佳的正则表达式是防止回溯的(.*?比字面序列的.*更具优势)或适当地滚动过不必要的内容(请参见这里获取一个很好的例子 - ,?[^,]*是神奇的!)。 - Unihedron

2

这里测试您可能的密码,看看它们是否给出正确的结果。

我使用的正则表达式是:

^(?=.*[a-z])(?=.*[A-Z])(?=.*?[0-9])(?=.*?[!#%])[A-Za-z0-9!#%]{8,32}$

抱歉,我误解了问题,认为是1个数字或1个特殊字符,因此我创建了一个非捕获的交替组。这是我的错误。 - skamazin
@Unihedron 我知道,我从你上面的链接中看到了你的答案。但是哪部分可以确保密码不会是 Aa!12345678;(仅作为示例)?哪部分防止使用 ;(分号)? - Jo Smo
2
@tastro 整个匹配都是由 ^$ 锚定的,因此 [...]{n,u} 将会断言该列表完全支持字符串区域。预查不影响匹配。 - Unihedron
2
正如Unihedron所指出的那样,前瞻不会捕获任何内容,因此所有捕获都发生在正则表达式的末尾;具体来说是这一部分:[A-Za-z0-9!#%]{8,32}。这将仅允许由大/小写字母、数字和 !#% 组成的字符串通过。因为 ; 没有被包含在内,所以它将无法匹配该正则表达式。如果您要将 ; 添加到列表中,它将允许该字符。[A-Za-z0-9!#%] 是一个白名单,意味着这些是唯一允许的字符。 - skamazin
@skamazin,现在我完全明白了。我只是不明白为什么我的正则表达式不起作用...我不知道前瞻不会捕获。谢谢你让我明白这一点! :) - Jo Smo
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接