2008-09-17 34 views
30

Tôi cần viết một hàm nhận chuỗi và regex. Tôi cần kiểm tra xem có phù hợp không và trả về vị trí bắt đầu và kết thúc của trận đấu. (Regex đã được biên soạn bởi qr//.)Làm thế nào tôi có thể tìm thấy vị trí của một trận đấu regex trong Perl?

Chức năng cũng có thể nhận được cờ "toàn cầu" và sau đó tôi cần phải trả về (bắt đầu, kết thúc) của tất cả các kết quả phù hợp.

Tôi không thể thay đổi regex, thậm chí không thêm () xung quanh nó khi người dùng có thể sử dụng ()\1. Có lẽ tôi có thể sử dụng (?:).

Ví dụ: đưa ra "ababab" và regex qr/ab/, trong trường hợp chung tôi cần phải lấy lại 3 cặp (bắt đầu, kết thúc).

+0

Nhìn vào diễn giải của Leon và của riêng tôi, bạn có thể muốn làm rõ liệu cờ có tương ứng với/g công cụ sửa đổi hay bất kỳ() nào chụp trong regex hay không. –

Trả lời

10

Hàm pos cho bạn vị trí của trận đấu. Nếu bạn đặt regex của bạn trong ngoặc đơn, bạn có thể nhận được độ dài (và do đó kết thúc) bằng cách sử dụng length $1. Giống như điều này

sub match_positions { 
    my ($regex, $string) = @_; 
    return if not $string =~ /($regex)/; 
    return (pos($string), pos($string) + length $1); 
} 
sub all_match_positions { 
    my ($regex, $string) = @_; 
    my @ret; 
    while ($string =~ /($regex)/g) { 
     push @ret, [pos($string), pos($string) + length $1]; 
    } 
    return @ret 
} 
+1

điều này trông hoàn toàn không chính xác. thay vì pos, sử dụng pos ($ string) trong all_match_positions, trong trường hợp khác, match_positions nó không hoạt động ở tất cả – Aftershock

+0

@Aftershock: bạn hoàn toàn đúng! Rất tiếc! –

0

Bạn cũng có thể sử dụng biến $ `không dùng nữa, nếu bạn sẵn sàng có tất cả RE trong chương trình của mình chạy chậm hơn. Từ perlvar:

$‘  The string preceding whatever was matched by the last successful pattern match (not 
      counting any matches hidden within a BLOCK or eval enclosed by the current BLOCK). 
      (Mnemonic: "`" often precedes a quoted string.) This variable is read-only. 

      The use of this variable anywhere in a program imposes a considerable performance penalty 
      on all regular expression matches. See "BUGS". 
17

Hãy quên bài đăng trước của tôi, tôi có ý tưởng hay hơn.

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

Kỹ thuật này không thay đổi regex theo bất kỳ cách nào.

Đã chỉnh sửa để thêm: để trích dẫn từ perlvar trên $ 1 .. $ 9. "Các biến này là tất cả chỉ đọc và được tự động dò tìm đến BLOCK hiện tại". Nói cách khác, nếu bạn muốn sử dụng $ 1 .. $ 9, bạn không thể sử dụng một chương trình con để thực hiện việc so khớp.

+0

Tôi nghĩ rằng điều này vẫn sẽ không hoạt động nếu có() trong regex – szabgab

+0

Vâng, xem ETA của tôi. –

+0

Bạn có thể sử dụng chương trình con để thực hiện khớp, nhưng bạn muốn các ảnh chụp bạn sẽ phải sử dụng substr(), @ - và @ + để trích xuất các kết quả phù hợp và trả lại cho người dùng. –

70

Biến tích hợp @-@+ giữ vị trí bắt đầu và kết thúc tương ứng của kết quả phù hợp thành công cuối cùng. $-[0]$+[0] tương ứng với toàn bộ mẫu, trong khi $-[N]$+[N] tương ứng với các phụ đề con số $N ($1, $2, v.v.).

+11

Những biến ma thuật này khiến tôi muốn cơn thịnh nộ đến từ Python; chúng không được nhắc đến ngay cả trong [perl re docs] (http://perldoc.perl.org/perlre.html). –

+5

perldoc perlvar ;-) – Phil

+3

Lưu ý rằng $ + [0] vv ("vị trí kết thúc") cung cấp chỉ mục của ký tự * sau * kết quả khớp, chứ không phải là ký tự cuối cùng của đối sánh. – TextGeek

0
#!/usr/bin/perl 

# search the postions for the CpGs in human genome 

sub match_positions { 
    my ($regex, $string) = @_; 
    return if not $string =~ /($regex)/; 
    return (pos($string), pos($string) + length $1); 
} 
sub all_match_positions { 
    my ($regex, $string) = @_; 
    my @ret; 
    while ($string =~ /($regex)/g) { 
     push @ret, [(pos($string)-length $1),pos($string)-1]; 
    } 
    return @ret 
} 

my $regex='CG'; 
my $string="ACGACGCGCGCG"; 
my $cgap=3;  
my @pos=all_match_positions($regex,$string); 

my @hgcg; 

foreach my $pos(@pos){ 
    push @hgcg,@$pos[1]; 
} 

foreach my $i(0..($#hgcg-$cgap+1)){ 
my $len=$hgcg[$i+$cgap-1]-$hgcg[$i]+2; 
print "$len\n"; 
} 
Các vấn đề liên quan