use strict; use warnings; my @toTest = ( q{Cont(ains balanced( nested Br(ack)ets )in t)he text}, q{Con(tains i(mbalan(ced Br(ack)ets, )one c)lose missing}, q{Contains i(mbalan(ced Br(ack)ets, )one op)en m)missing}, q{No brackets in this string}, q{Won)ky br(ackets in) this s(tring}, q{More wonky br(ackets in) th)is s(tring}, q{Just the one( leading bracket}, q{And just th)e one trailing bracket}, q{So(me m(ultip)le n(est(s in) thi)s o)ne}, q{Ther(e is( mo(re) de(e)p )nes(ti(n(g i)n (mul)ti)p(l)es) he)re}, q{Th(er(e is( mo(re) de(e)p )nes(ti(n(g i)n (mul)ti)p(l)es) he)re}, q{Ther(e is( mo(re) de(e)p )nes(ti(n(g i)n (mul)ti)p(l)es) he)r)e}, q{Ther(e is( mo(re) de(e)p )n(es(ti(n(g i)n (mul)ti)p(l)es) he)re}, q{Some d((oub)le b)rackets}, q{(Some d((oub)le b)rackets)}, q{ab(())cde}, q{ab(c(d)e}, q{ab(c)d)e}, q{ab(c)de}, ); my @memoList; my $rxNest; $rxNest = qr {(?x) ( \( [^()]* (?: (??{$rxNest}) [^()]* )* \) ) (?{ [ @{$^R}, $^N ] }) }; my $rxOnlyNested; { use re q(eval); $rxOnlyNested = qr {(?x) (?{ [] }) ^ [^()]* (?: $rxNest [^()]* )+ \z (?{ @memoList = @{$^R} }) }; } testString($_) for @toTest; sub testString { my $string = shift; @memoList = (); print qq{\nString: $string\n}; if($string =~ /$rxOnlyNested/) { print qq{ Match succeeded\n}; print qq{ ---------------\n}; print qq{ Before brackets:-\n}; print qq{ -->@{[substr $string, 0, $-[1]]}<--\n}; print qq{ Bracket pairs:-\n}; print qq{ $_\n} for @memoList; print qq{ After brackets:-\n}; print qq{ -->@{[substr $string, $+[1]]}<--\n}; } else { print qq{ Match failed\n}; } }