2011-11-29 72 views
6

我寫了一個驗證輸入字符串的正則表達式。它必須有8個字符的最小長度(由字母數字和標點符號組成),它必須至少有一個數字和一個字母字符。所以我想出正則表達式:如何在正則表達式中替換lookahead?

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

現在我要重寫這個表達式中不支持先行語言,我應該怎麼重寫正則表達式?

有效的輸入是:

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

無效輸入:

fooo,bar 
1234-567 
.1234567 
+2

陳述的語言也許會有幫助,因爲對於不同功能的支持有所不同。 – fncomp

+0

@Josh:問題被標記爲「perl」。 –

+1

@mu是否有Perl的實現不支持預見? – fncomp

回答

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 
+0

你的第二個正則表達式是很多重複的工作。使用兩個單獨的正則表達式來檢查一個alpha和一個數字:qr/[az]/i和qr/[0-9 –

+0

@MetaEd我正在尋找一個單行的正則表達式,但是沒有使用一個簡單的正則表達式功能像lokkahead。我會和你的第二個解決方案一起去。謝謝 – alexyz78

0

我可以想出現在最好的是

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

但你必須檢查的長度字符串分開。

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(); 
+0

我把它標記爲'Perl',因爲我必須將它從Perl移植到Oracle。我沒有指定'目標'語言,因爲有幾種語言不支持超前語言,因爲我對正則表達式本身比實現語言更感興趣。 – alexyz78

0

我玩的這些想法,以獲得最佳性能:

  • 應該是短期有效的更快投入,但會像「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]'))