Questa non è una cosa che può essere risolta con una sola
espressione regolare, indipendentemente da quanto complessa essa sia. Per
trovare qualcosa compreso tra due caratteri singoli, uno schema come
/x([^x]*)x/ memorizzerà in $1 i caratteri contenuti nel mezzo. In
caso di caratteri multipli, sarà necessario qualcosa come
/alpha(.*?)omega/. Tuttavia, nessuna di queste soluzioni sarà
in grado di gestire gli annidamenti. Per espressioni bilanciate che usano
(, {, [ o < come delimitatori, usate il modulo Regexp::Common
da CPAN, o consultate perlre/(??{ code }). Negli altri casi, dovrete
scrivervi un parser.
Se siete seriamente intenzionati a scrivere un parser, esiste un certo
numero di moduli e strumenti che vi renderanno la vita molto più
facile. Ci sono i moduli CPAN Parse::RecDescent, Parse::Yapp, e
Text::Balanced; ed il programma byacc. A partire da perl 5.8, Text::Balanced
fa parte della distribuzione standard.
Un approccio semplice, dall'interno e distruttivo che potreste voler provare,
consiste nel tentare di estrarre le parti più piccole una alla volta:
while (s/BEGIN((?:(?!BEGIN)(?!END).)*)END//gs) {
# fate qualcosa con $1
}
Un approccio più complesso e tortuoso consiste nel far fare il lavoro
alle espressioni regolari del perl al posto vostro. Il seguente
codice è di Dean Inada, e sembra partecipare all'Obfuscated Perl
Contest, ma funziona davvero:
# $_ contiene la stringa da analizzare
# BEGIN ed END sono i delimitatori di apertura e chiusura per il
# testo tra essi compreso.
@( = ('(','');
@) = (')','');
($re=$_)=~s/((BEGIN)|(END)|.)/$)[!$3]\Q$1\E$([!$2]/gs;
@$ = (eval{/$re/},$@!~/unmatched/i);
print join("\n",@$[0..$#$]) if( $$[-1] );
|