#!/usr/bin/perl use warnings; use strict; use Data::Dumper; my $input = '(a,b,(c,d,(e,f,g)))'; print Dumper parse_expression($input); sub parse_expression { my $exp = shift; my @tokens = (); $exp=~s/\s*([()])\s*/ $1 /go; # Get tokens push @tokens, $1 while $exp=~/\G\s*(".*?")/gc or $exp=~/\G\s*('.*?')/gc or $exp=~/\G\s*(\S+)/gc; # Find any parens. my (@lp,@rp) = (); for (my $p =0; $p < @tokens; $p++){ if ($tokens[$p] eq '('){ push @lp,$p; }elsif($tokens[$p] eq ')'){ push @rp,$p; } } if ( @lp != @rp){ warn "Mismatched parens in expression.\n"; return; } my @temp = @tokens; for (my $i=0; $i < @rp; $i++){ my @wanted; for (my $j = $#lp; $j >= 0 ; $j--){ if ( defined $lp[$j] && $lp[$j] < $rp[$i] ){ (undef,@wanted) = @tokens[ $lp[$j] .. ($rp[$i] - 1 ) ] ; @tokens[ $lp[$j] .. ($rp[$i]) ] = [ grep {defined $_ } @wanted]; push @temp, map {split /\s*,\s*/} @wanted; $lp[$j] = $rp[$i] = undef; last; } } } return $tokens[0]; } __DATA__ # OUTPUT $VAR1 = [ 'a,b,', [ 'c,d,', [ 'e,f,g' ] ] ];