如何在正则表达式中替换前瞻?

时间:2011-11-29 05:55:34

标签: regex oracle

我写了一个验证输入字符串的正则表达式。它必须至少有8个字符长度(由字母数字和标点字符组成),并且必须至少有一个数字和一个字母字符。所以我想出了正则表达式:

^(?=.*[0-9])(?=.*[a-zA-Z])[a-zA-Z0-9-,._;:]{8,}$

现在我必须用不支持前瞻的语言重写这个正则表达式,我应该如何重写那个正则表达式呢?

有效输入是:

1foo,bar
foo,bar1
1fooobar
foooobar1
fooo11bar
1234x567
a1234567

输入无效:

fooo,bar
1234-567
.1234567

4 个答案:

答案 0 :(得分:7)

有两种方法。一种是组成一个处理所有可能替代方案的表达式:

^[a-zA-Z][0-9][a-zA-Z0-9-,._;:]{6,}$
  |
^[a-zA-Z][a-zA-Z0-9-,._;:][0-9][a-zA-Z0-9-,._;:]{5,}$
  |
^[a-zA-Z][a-zA-Z0-9-,._;:]{2}[0-9][a-zA-Z0-9-,._;:]{4,}$

等。这是一个组合的噩梦,但它会起作用。

更简单的方法是使用两个表达式两次验证相同的字符串:

^[a-zA-Z0-9-,._;:]{8,}$          # check length and permitted characters

<击>

<击>
[a-zA-Z].*[0-9]|[0-9].*[a-zA-Z]  # check required characters

<击>

编辑:@briandfoy正确指出分别搜索每个必需字符会更有效率:

[a-zA-Z]                         # check for required alpha

[0-9]                            # check for required digit

答案 1 :(得分:2)

此问题原始标记为perl,这就是我的答案。对于oracle的东西,我不知道你怎么做同样的事情。但是,我会尝试在它到目前为止验证这些东西。

我不会在一个正则表达式中这样做。当您决定更改规则时,您将获得相同数量的工作来制作新的正则表达式。即使它们可用,我也不会使用外观,因为我不想容忍所有的回溯。

这看起来像是很多代码,但解决问题的部分只是子程序。它有非常简单的模式。密码规则更改后,您可以添加或删除模式。使用study可能是值得的,但我没有调查:

use v5.10;
use strict;

use Test::More;

my @valids = qw(
    1foo,bar
    foo,bar1
    1fooobar
    foooobar1
    fooo11bar
    );

my @invalids = qw( 
    fooo,bar
    short
    nodigitbutlong
    12345678
    ,,,,,,,,
    );

sub is_good_password {
    my( $password ) = @_;

    state $rules = [
        qr/\A[A-Z0-9,._;:-]{8,}\z/i,
        qr/[0-9]/,
        qr/[A-Z]/i,
        ];

    foreach my $rule ( @$rules ) {
        return 0 unless $password =~ $rule;
        }

    return 1;
    }       

foreach my $valid ( @valids ) {
    ok( is_good_password( $valid ), "Password $valid is valid" );
    }

foreach my $invalid ( @invalids ) {
    ok( ! is_good_password( $invalid ), "Password $invalid is invalid" );
    }

done_testing();

答案 2 :(得分:0)

我现在能想到的最好的是

(.*[a-zA-Z].*[0-9].*|.*[0-9].*[a-zA-Z].*)

但你必须分别检查字符串的长度。

答案 3 :(得分:0)

我会利用这些想法来获得最佳效果:

    对于短有效输入,
  • 应该更快,但对于“0a000000000000000000”或“aaaaaaaaaaaaaaa”等输入,它会更慢(回溯):

    regexp_like(regexp_substr(input_string, '^[a-zA-Z0-9_,.;:-]{8,}$'),
                '[0-9].*[a-zA-Z]|[a-zA-Z].*[0-9]')
    
  • 如果有很多无效输入,
  • 应该更快(不要错过第二行的[^ ...]):

    (length(input_string) >= 8 and
     not regexp_like(input_string, '[^a-zA-Z0-9_,.;:-]') and
     regexp_like(input_string, '[a-zA-Z]') and
     regexp_like(input_string, '[0-9]'))