Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Matching nested parens

by BernieC (Pilgrim)
on Oct 01, 2020 at 19:23 UTC ( [id://11122430]=perlquestion: print w/replies, xml ) Need Help??

BernieC has asked for the wisdom of the Perl Monks concerning the following question:

Supersearch didn't turn anything up and I can't figure out if Parse::RecDescent will do this:

What I want is a subroutine that matches a set of nested parens. That is, what I'd like is:

$str = "(a a (a a)(a a))(b b(b)b b)" and have my ($parens, $rest) = match($str) ;
and have $parens end up with "a a (a a)(a a)" and $rest be "(b b(b)b b)" I seem to recall doing something like this when I was an undergraduate and it involved something like counting parens [that is, count +1 for a ( and -1 for a ) and you've got the first balanced set when the count == 0. Is there a more elegant way to do it in Perl?

Replies are listed 'Best First'.
Re: Matching nested parens
by haukex (Archbishop) on Oct 01, 2020 at 19:41 UTC

    I would suggest Regexp::Common:

    use warnings; use strict; use Data::Dump; use Regexp::Common qw/balanced/; "(a a (a a)(a a))(b b(b)b b)" =~ /$RE{balanced}{-parens=>'()'}/; dd $&, $'; # ("(a a (a a)(a a))", "(b b(b)b b)")

    Though of course there are plenty of other solutions, including Parse::RecDescent, though that might be a little overkill if this is all you're doing. See e.g. regex for nested "<"/">', and note that Text::Balanced is a core module.

      Thanks for the advice. Looks like Regexp::Common is just what I wanted {I've just cpan installed it :o)}
        A footnote. I was curious about Regexp::Common. So:
        use Regexp::Common qw/balanced/; say $RE{balanced}{-parens=>'()'} ;
        And I can now see why I didn't have a hope of figuring out the RE on my own... :o)
Re: Matching nested parens
by perlfan (Vicar) on Oct 06, 2020 at 16:50 UTC
    An alternative approach is to iterate over each charactor; when you see a ( push it on the stack array (and change some "state" variable, maybe a "depth count" which is also the size of the stack); then when you see a ), pop the top of the stack (will be a (). Based on the depth of the nesting (or size of the stack) you can do all sorts of things with the intervening characters you see.

      Note that there is no need to track stack depth independently in Perl if you use an array as your stack with the push and pop builtins: Perl will keep track of the array length, which is accessible either by using the array in scalar context or with the $# sigil. There is an important difference: scalar @array gives the number of elements in @array (0 if @array is empty, 1 if there is one element) while $#array gives the highest index in @array (-1 if @array is empty, 0 if there is one element).

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11122430]
Approved by haukex
Front-paged by haj
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (5)
As of 2024-04-24 19:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found