正则表达式 - 只有一个特殊字符

时间:2016-01-28 11:24:02

标签: regex conditional-statements

我目前正在使用我为密码创建的正则表达式。

必须尊重这个条件:

  • 8个字符
  • 至少一个MAJ(A-Z)
  • 至少一分钟(a-z)
  • 至少一位数字(0-9)
  • 来自以下的一个特殊字符:。,:;'!@#$%^& * _ + = |(){} [? - ] / \
  • 禁止使用以下字符:<>`

这是正则表达式:

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

一切正常,但现在,我希望它接受只有一个特殊字符

我搜索并尝试了很多事情(例如,在组末尾有{1}),但它根本不起作用! Aa1 ;; aaa 等结果仍然匹配..

有人可以告诉我该怎么做?

2 个答案:

答案 0 :(得分:2)

真的 - 我不会这样做。首先 - 挑剔的密码规则不是一个好主意。它们降低了安全性,因为它们减少了密钥空间。

但更基本的是 - 统治所有人的正则表达不是一个好的设计策略。你现有的正则表达式足够长且复杂,以至于维护程序员将不得不花费一些时间来弄清楚它的作用,如果它在将来发生变化......你将再次经历这种头痛。

所以我要提供一个替代方案 - 打破你的正则表达式,单独应用验证标准,并给出消息说明它失败的原因。这样的事情(用你正在使用的任何语言实现):

#!/usr/bin/env perl
use strict;
use warnings;

while ( <DATA> ) {
    chomp;
    my $fail = 0; 
    print "Testing: \"$_\"\n"; 

    if (not m/.{8}/) { 
        print "Rejected because less than 8 chars\n"; 
        $fail++;
    }
    if ( not m/[A-Z]/ ) { 
         print "Rejected - needs at least one upper case character\n";
         $fail++;
    }
    if ( not m/\d/ ) { 
        print "Rejected - needs at least one digit\n"; 
         $fail++;
    }
    if ( my @matches =  m/([.,:;\'!@#$%^&*_+=|(){}[?\-\]\/\\])/g ) {
        if ( @matches != 1 ) { 
                print "Rejected - exactly one special character, not more\n";
                $fail++; 
        }
    } 
    else {
        print "Rejected - needs a special character\n";
        $fail++; 
    }
    if ( m/[\<\>\`]/ ) { 
        print "Rejected - \"<>`\" not permited\n";
        $fail++; 
    }
    if ( not $fail ) { 
        print "$_ is OK\n";
    }
}

__DATA__
Fish1234!
!!moooMoo33
helloMum

这给出了:

Testing: "Fish1234!"
Fish1234! is OK
Testing: "!!moooMoo33"
Rejected - exactly one special character, not more
Testing: "helloMum"
Rejected - needs at least one digit
Rejected - needs a special character

(虽然我注意到 - Fish1234!并不是一个强大的密码,即使它确实通过了您的规则)

答案 1 :(得分:1)

怎么样:

^(?=.{8}$)(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?!.*[<>`])([^.,:;'!@#$%^&*_+=|(){}[?\-\]\/\\]*)[.,:;'!@#$%^&*_+=|(){}[?\-\]\/\\](?1)$

DEMO

用前瞻检查长度,然后确保它只有一个特殊的字符,在它之前和之后有不同的东西

(?1)是对第一组模式的引用,您可以将其替换为[^.,:;'!@#$%^&*_+=|(){}[?\-\]\/\\]*如果您希望或不支持您的工具

DEMO

或者,在保留原始语法的同时:

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

以下是压缩版本:(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?!.*[<>`])(?=[^.,:;'!@#$%^&*_+=|(){}[?\-\]\/\\]*[.,:;'!@#$%^&*_+=|(){}[?\-\]\/\\][^.,:;'!@#$%^&*_+=|(){}[?\-\]\/\\]*$).{8}$

DEMO