3

我是 RegEx 的新手,已经做了很多搜索,但没有找到任何具体的东西。

我正在编写一个验证密码字符串的正则表达式。可接受的字符串必须至少有 4 种字符类型中的 3 种:数字、小写、大写、特殊字符 [<+$*)],但不得包含另一组特殊字符 (|;{})。

我对包含有一个想法(也就是说,如果它是正确的方法)。

它看起来像这样:

^((a-z | A-Z |\d)(a-z|A-Z|[<+$*])(a-z|[<+$*]|\d)(A-Z|[<+$*]|\d)).*$

如何确保用户不输入特殊字符(|;{})这是我尝试使用排除字符串的方法:

^(?:(?![|;{}]).)*$

我尝试了一些技巧将两者结合在一个正则表达式中,但无法使其正常工作。

关于如何正确执行此操作的任何输入?

4

3 回答 3

9

不要试图在一个正则表达式中完成所有操作。 进行两次不同的检查。

假设您正在使用 Perl(因为您没有指定语言):

$valid_pw =
    ( $pw =~ /^((a-z | A-Z |\d)(a-z|A-Z|[<+$*])(a-z|[<+$*]|\d)(A-Z|[<+$*]|\d)).*$/ ) &&
    ( $pw !~ /\|;{}/ );

您是说“如果 PW 匹配所有包含规则,并且 PW 不匹配任何排除字符,则密码有效。”

看看这比上面@Jerry 的回复更清楚:

^(?![^a-zA-Z]*$|[^a-z0-9]*$|[^a-z<+$*]*$|[^A-Z0-9]*$|[^A-Z<+$*]*$|[^0-9<+$*]*$|.*[|;{}]).*$

我不怀疑 Jerry 的版本可以工作,但你想维护哪一个?

事实上,你可以进一步分解它并且非常清楚:

my $cases_matched = 0;
$cases_matched++ if ( $pw =~ /\d/ );       # digits
$cases_matched++ if ( $pw =~ /[a-z]/ );    # lowercase
$cases_matched++ if ( $pw =~ /[A-Z]/ );    # uppercase
$cases_matched++ if ( $pw =~ /<\+\$\*/ );  # special characters

my $is_valid = ($cases_matched >= 3) && ($pw !~ /\|;{}/); # At least 3, and none forbidden.

当然,这占用了 6 行而不是 1 行,但是在一年中,当您回过头来必须添加新规则或弄清楚代码的作用时,您会很高兴以这种方式编写它。

仅仅因为你可以在一个正则表达式中做到这一点并不意味着你应该

于 2013-09-04T19:37:16.650 回答
2

您当前的正则表达式不适用于强制执行至少 3 of 4 的要求。为此使用正则表达式会变得相当复杂,但在我看来,最好的方法是使用包含所有失败案例的否定前瞻,这样如果遇到任何否定案例,整个匹配都会失败。在这种情况下,“至少 4 个组中的 3 个”要求也可以描述为“如果未找到任何 2 个组则失败”。这也使得添加最终要求以确保找不到任何字符变得非常容易[|;{}]

^               # beginning of string anchor
(?!             # fail if
   [^a-zA-Z]*$     # no [a-z] or [A-Z] anywhere
     |             # OR
   [^a-z0-9]*$     # no [a-z] or [0-9] anywhere
     |             # OR
   [^a-z<+$*]*$    # no [a-z] or [<+$*] anywhere
     |             # OR
   [^A-Z0-9]*$     # no [A-Z] or [0-9] anywhere
     |             # OR
   [^A-Z<+$*]*$    # no [A-Z] or [<+$*] anywhere
     |             # OR
   [^0-9<+$*]*$    # no [0-9] or [<+$*] anywhere
     |             # OR
   .*[|;{}]        # a character from [|;{}] exists
)
.*$             # made it past the negative cases, match the entire string

这是一行:

^(?![^a-zA-Z]*$|[^a-z0-9]*$|[^a-z<+$*]*$|[^A-Z0-9]*$|[^A-Z<+$*]*$|[^0-9<+$*]*$|.*[|;{}]).*$

示例:http ://rubular.com/r/4YV6Aj0vqh

于 2013-09-04T19:07:58.867 回答
1

这是为了只接受你提到的字符:

^(?:(?=.*[0-9])(?=.*[a-z])(?=.*[<+$*)])|(?=.*[a-z])(?=.*[<+$*)])(?=.*[A-Z])|(?=.*[0-9])(?=.*[A-Z])(?=.*[<+$*)])|(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]))[0-9A-Za-z<+$*)]+$

这一个适用于您提到的所有字符,以及除 . 之外的任何特殊字符|;{}

^(?:(?=.*[0-9])(?=.*[a-z])(?=.*[<+$*)])|(?=.*[a-z])(?=.*[<+$*)])(?=.*[A-Z])|(?=.*[0-9])(?=.*[A-Z])(?=.*[<+$*)])|(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]))(?!.*[|;{}].*$).+$

(一个区别是第一个正则表达式不接受特殊字符@,但第二个接受)。

我也使用过+,因为密码在逻辑上不能为 0 宽度。

但是,它很长,比 FJ 的正则表达式长,哦,好吧。那是因为我正在使用积极的前瞻,这需要更多的检查。

于 2013-09-04T19:23:29.597 回答