2012-10-04 35 views
7

Tôi đang cố gắng khớp văn bản như sp { ...{...}... }, trong đó các dấu ngoặc nhọn được phép lồng. Đây là những gì tôi có cho đến thời điểm này:Regex với biểu thức đệ quy để khớp với niềng răng lồng nhau?

my $regex = qr/ 
(     #save $1 
    sp\s+   #start Soar production 
    (    #save $2 
     \{   #opening brace 
     [^{}]*  #anything but braces 
     \}   #closing brace 
     | (?1)  #or nested braces 
    )+    #0 or more 
) 
/x; 

Tôi không thể làm cho nó khớp với văn bản sau đây: sp { { word } }. Bất cứ ai có thể nhìn thấy những gì là sai với regex của tôi?

Trả lời

6

Có nhiều sự cố. Bit đệ quy nên là:

(
    (?: \{ (?-1) \} 
    | [^{}]+ 
    )* 
) 

Tất cả với nhau:

my $regex = qr/ 
    sp\s+ 
    \{ 
     (
     (?: \{ (?-1) \} 
     | [^{}]++ 
     )* 
    ) 
    \} 
/x; 

print "$1\n" if 'sp { { word } }' =~ /($regex)/; 
+0

Chỉ cần những gì tôi cần. –

+0

Gần như tôi có thể nói, regex không cho phép khoảng trống xung quanh niềng răng (xin lỗi cho vần điệu) nên trường hợp thử nghiệm sẽ thất bại. Có chuyện gì thế? – tripleee

+0

Hmmm ... Điều này kết thúc mãi mãi cho một số trận đấu một phần, như thế này: 'sp {word {(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa)}'. –

5

Đây là trường hợp cho underused Text::Balanced, một mô-đun lõi rất tiện dụng cho các loại hình điều. Nó dựa trên pos của sự bắt đầu của chuỗi phân được tìm thấy/set đầu tiên, vì vậy tôi thường gọi nó như thế này:

#!/usr/bin/env perl 

use strict; 
use warnings; 

use Text::Balanced 'extract_bracketed'; 

sub get_bracketed { 
    my $str = shift; 

    # seek to beginning of bracket 
    return undef unless $str =~ /(sp\s+)(?={)/gc; 

    # store the prefix 
    my $prefix = $1; 

    # get everything from the start brace to the matching end brace 
    my ($bracketed) = extract_bracketed($str, '{}'); 

    # no closing brace found 
    return undef unless $bracketed; 

    # return the whole match 
    return $prefix . $bracketed; 
} 

my $str = 'sp { { word } }'; 

print get_bracketed $str; 

Các regex với modifier gc kể chuỗi để nhớ nơi điểm cuối của trận đấu là, và extract_bracketed sử dụng thông tin đó để biết bắt đầu từ đâu.

+0

Tôi thực sự cần phải đọc về mô-đun này. Nó xuất hiện rất nhiều, nhưng tôi luôn thích regex bởi vì tôi đã đầu tư quá nhiều thời gian vào việc học nó, thật thú vị khi học nhiều hơn, và có vẻ nhỏ gọn hơn. Cảm ơn câu trả lời! –

+0

@NateGlenn, nó thực sự bổ sung cho regexp và đặc biệt là chức năng regexp 'gc' (parser). Đây là lý do tại sao nó sử dụng 'pos' của chuỗi, vì dự kiến ​​bạn sẽ xen kẽ các cuộc gọi đến' text_balanced' với '// gc' –

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