Как заменить lookahead в регулярных выражениях? - PullRequest
6 голосов
/ 29 ноября 2011

Я написал регулярное выражение, которое проверяет входную строку.Он должен иметь минимальную длину 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 ]

7 голосов
/ 29 ноября 2011

Есть два подхода. Одним из них является составление одного выражения, которое обрабатывает все возможные альтернативы:

^[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
2 голосов
/ 29 ноября 2011

Этот вопрос был изначально помечен как perl, и вот как я на него ответил.Что касается оракула, я понятия не имею, как бы вы поступили так же.Тем не менее, я бы попробовал проверить этот материал до того, как он зашёл так далеко.

Я бы не стал делать это в одном регулярном выражении.Когда вы решите изменить правила, у вас будет столько же работы для создания нового регулярного выражения.Я не стал бы использовать обходные пути для этого, даже если бы они были доступны, поскольку я не хотел бы мириться с возвратом.

Похоже, что это много кода, но часть, которая решает вашу проблему - этоподпрограмма.У этого есть очень простые образцы.Когда правила пароля меняются, вы добавляете или удаляете шаблоны.Возможно, стоит использовать исследование , но я не исследовал это:

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();
0 голосов
/ 16 февраля 2012

Я бы поэкспериментировал с этими идеями, чтобы добиться максимальной производительности:

  • должно быть быстрее для коротких допустимых входов, но будет медленнее (возврат) для входов типа «0a000000000000000000» или «aaaaaaaaaaaaaaa»:

    regexp_like(regexp_substr(input_string, '^[a-zA-Z0-9_,.;:-]{8,}$'),
                '[0-9].*[a-zA-Z]|[a-zA-Z].*[0-9]')
    
  • должно быть быстрее, если много неправильных входных данных (не пропустите [^ ...] во 2-й строке):

    (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]'))
    
0 голосов
/ 29 ноября 2011

Лучшее, что я могу придумать сейчас, это

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

Но вы должны проверить длину строки отдельно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...