2017-08-17 17 views
6

tôi có thể nhìn thấy từ this câu trả lời rằng nếu tôi làmLàm cách nào tôi có thể tìm thấy các vị trí _all_ của một đối sánh regex trong Perl?

sub match_all_positions { 
    my ($regex, $string) = @_; 
    my @ret; 
    while ($string =~ /$regex/g) { push @ret, $-[0] } 
    return @ret 
} 

print join ',', match_all_positions('0{3}', '001100010000'); 

tôi nhận được

4,8 

gì tôi cần phải làm để có được các chỉ số của tất cả trận đấu, ngay cả khi sự chồng chéo, chẳng hạn như vị trí 8 và 9 trong ví dụ trên?

tôi có thể làm

sub match_all_positions_b { 
    my ($substr, $string) = @_; 
    return unless index($string, $substr) > 0; 
    my @res; 
    my $i = 0; 
    while ($i <= (length($string) - $length)) { 
     $i = index($string, $substr, $i); 
     last if $i < 0; 
     push @res, $i++; 
    } 
    return @res; 
} 

print join ',', match_all_positions_b('000', '001100010000'); 

mà chỉ cho phép tôi kết hợp một chuỗi con, hoặc

sub match_all_positions_c { 
    my ($substr, $string) = @_; 
    my $re = '^' . $substr; 
    my @res; 
    for (0..(length($string) - $length)) { 
     push @res, $_ if substr($string, $_) =~ /$re/; 
    } 
    return @res; 
} 

print join ',', match_all_positions_c('0{3}', '001100010000'); 

Đó là gấp đôi chậm.

có cách nào để nhận được tất cả các trận đấu, ngay cả khi chúng trùng lặp? Hoặc tôi nên chỉ mất tốc độ vì nó vốn có để sử dụng các trận đấu regex?

+1

Một số dữ liệu mẫu sẽ có ích. Tiêu chuẩn 'lừa' cho các kết quả trùng lặp là xác nhận chiều rộng bằng 0. – Sobrique

+0

@Sobrique - để xem dữ liệu ví dụ về mã. 'match_all_positions ('0 {3}', '001100010000');' sẽ trả về '(4, 8, 9)'; 'match_all_positions ('2 {3}', '001100010000');' phải trả về '()'; – simone

Trả lời

7

Bạn cần cập nhật regex của mình cho zero-width look-ahead đối sánh.

Thử gọi chức năng của bạn như thế này:

print join ',', match_all_positions('(?=0{3})', '001100010000'); 
+1

nó hoạt động. Bây giờ tôi chỉ cần đọc các tài liệu và tìm ra lý do tại sao. Cảm ơn! Và nó cũng rất nhanh. – simone

+3

Đó là vì biểu thức thông thường _consume_ và do đó, một kết quả phù hợp sẽ xóa các mục con khỏi nhóm. Zero chiều rộng không tiêu thụ, nó 'đặt công cụ trở lại' để được tái sử dụng. – Sobrique

0

Nếu bạn muốn tìm các vị trí mà tại đó nó phù hợp:

my @matches; 
push @matches, "$-[1]:$+[1]" while "aabbcc" =~ /(?=(a.*c))/sg; 

Output:

0:6 
1:6 

Nếu bạn muốn tất cả các trận đấu có thể,

local our @matches; 
"aabbcc" =~ /(a.*?c)(?{ push @matches, "$-[1]:$+[1]" })(?!)/s; 

Output:

0:5 
0:6 
1:5 
1:6 
+0

Thực sự rất hay - nhưng yêu cầu một số suy nghĩ :-) – pitseeker

Các vấn đề liên quan