2012-10-04 34 views
7

Sto tentando di abbinare il testo come sp { ...{...}... }, dove è consentito il nidificazione delle parentesi graffe. Questo è quello che ho finora:Regex con espressione ricorsiva per abbinare le parentesi graffe nidificate?

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; 

non riesco proprio a farlo per abbinare il seguente testo: sp { { word } }. Qualcuno può vedere cosa c'è di sbagliato nella mia espressione regolare?

risposta

6

Ci sono numerosi problemi. Il bit dovrebbe essere ricorsiva:

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

Tutti insieme:

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

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

Proprio quello di cui avevo bisogno. –

+0

Per quanto posso dire, la regex non consente spazi attorno alle parentesi graffe (mi dispiace per la rima), quindi il test case dovrebbe fallire. Cosa succede con quello? – tripleee

+0

Hmmm ... Questo finisce per prendere per sempre alcune corrispondenze parziali, come questa: 'sp {word {(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}}'. –

5

Si tratta di caso per il sottoutilizzata Text::Balanced, un modulo di base molto utile per questo genere di cose. Essa si basa sul pos di inizio della sequenza delimitata essere trovato/set prima, così io di solito invocare in questo modo:

#!/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; 

L'espressione regolare con il modificatore gc dice la stringa di ricordare dove il punto finale di la partita è, e extract_bracketed usa queste informazioni per sapere da dove iniziare.

+0

Ho davvero bisogno di leggere questo modulo. Ne deriva molto, ma preferisco sempre regex perché ho già investito così tanto tempo nell'apprenderlo, è divertente imparare di più e sembra più compatto. Grazie per la risposta! –

+0

@NateGlenn, è in realtà complementare a regexp e in particolare alla funzionalità regexp 'gc' (parser). Questo è il motivo per cui usa il 'pos' della stringa, perché ci si aspetta che tu mescoli le chiamate a' text_balanced' con '// gc' –

Problemi correlati