2011-11-29 40 views
6

Tôi đã viết một regex xác nhận chuỗi đầu vào. Nó phải có độ dài tối thiểu 8 ký tự (được tạo thành bởi ký tự chữ và số và dấu chấm câu) và nó phải có ít nhất một chữ số và một chữ cái char. Vì vậy, tôi đã đưa ra các regex:Làm thế nào để thay thế lookahead trong regex?

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

Bây giờ tôi phải viết lại regex này bằng ngôn ngữ không hỗ trợ lookahead, tôi nên viết lại regex đó như thế nào?

đầu vào hợp lệ là:

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

đầu vào không hợp lệ:

fooo,bar 
1234-567 
.1234567 
+2

Nêu các ngôn ngữ có thể giúp đỡ, vì hỗ trợ cho các tính năng khác nhau thay đổi. – fncomp

+0

@Josh: Câu hỏi được gắn thẻ "perl". –

+1

@mu Có triển khai Perl không hỗ trợ giao diện không? – fncomp

Trả lời

7

Có hai cách tiếp cận. Một là để soạn một biểu thức xử lý tất cả các lựa chọn thay thế có thể:

^[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,}$ 

vv Đây là một cơn ác mộng kết hợp, nhưng nó sẽ hoạt động.

Một cách tiếp cận đơn giản hơn nhiều là để xác nhận cùng một chuỗi hai lần sử dụng hai biểu thức:

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

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

EDIT: @briandfoy chỉ một cách chính xác ra rằng nó sẽ hiệu quả hơn để tìm kiếm cho mỗi nhân vật được yêu cầu riêng:

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

[0-9]       # check for required digit 
+0

Regex thứ hai của bạn là rất nhiều công việc lặp đi lặp lại. Sử dụng hai regex riêng biệt để kiểm tra alpha và một số: qr/[az]/i và qr/[0-9 –

+0

@MetaEd. Tôi đang tìm một regex đơn, nhưng không phải là một thứ tầm thường mà không sử dụng tính năng như lokkahead. Tôi sẽ đi với giải pháp thứ 2 của bạn. Cảm ơn – alexyz78

0

Điều tốt nhất tôi có thể đưa ra ngay bây giờ là

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

Nhưng bạn phải kiểm tra độ dài của chuỗi riêng biệt.

2

Câu hỏi này đã được ban đầu được gắn thẻ như perl, và đó là cách tôi đã trả lời nó. Đối với những thứ oracle, tôi không có ý tưởng làm thế nào bạn muốn làm điều tương tự. Tuy nhiên, tôi sẽ cố gắng xác nhận những thứ này trước khi nó đi xa đến thế.

Tôi sẽ không làm điều này trong một cụm từ thông dụng. Khi bạn quyết định thay đổi các quy tắc, bạn sẽ có cùng một lượng công việc để tạo biểu thức chính quy mới. Tôi sẽ không sử dụng giải pháp cho điều này ngay cả khi họ đã có sẵn vì tôi sẽ không muốn chịu đựng tất cả các backtracking.

Có vẻ như đó là rất nhiều mã, nhưng phần giải quyết vấn đề của bạn chỉ là chương trình con. Nó có các mẫu rất đơn giản. Khi các quy tắc mật khẩu thay đổi, bạn thêm hoặc xóa các mẫu.Nó có thể là giá trị nó để sử dụng study, nhưng tôi đã không điều tra rằng:

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

Tôi đã gắn thẻ nó là 'Perl' vì tôi đã chuyển nó từ Perl sang Oracle. Tôi đã không chỉ định ngôn ngữ 'đích' vì có một số ngôn ngữ không hỗ trợ lookahead và bởi vì tôi quan tâm nhiều đến chính bản thân hơn so với ngôn ngữ triển khai. – alexyz78

0

tôi sẽ chơi xung quanh với những ý tưởng để có được hiệu suất tốt nhất:

  • nên nhanh hơn cho ngắn hợp lệ đầu vào, nhưng sẽ chậm hơn (backtrack) vì những đóng góp như "0a000000000000000000" hoặc "aaaaaaaaaaaaaaa":

    regexp_like(regexp_substr(input_string, '^[a-zA-Z0-9_,.;:-]{8,}$'), 
          '[0-9].*[a-zA-Z]|[a-zA-Z].*[0-9]') 
    
  • nên nhanh hơn nếu có nhiều không hợp lệ đầu vào (không bỏ lỡ [^ ...] trên dòng thứ 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]')) 
    
Các vấn đề liên quan