use strict; use warnings; use Data::Dumper; my $s = <<'END'; sys ecm cloud-provider /Common/aws-ec2 { description "The aws-ec2 parameters" property-template { account { } availability-zone { valid-values { a b c d } } instance-type { valid-values { t2.micro t2.small t2.medium } } region { valid-values { us-east-1 us-west-1 } } } } END my %valid_keys = map { $_, 1 } qw/ description property-template account availability-zone instance-type valid-values region /; $s =~ s/ (?| "([^"{}]+)" | (?:^|(?<=\s)) ([^\s{}]+) (?:$|(?=\s)) ) /"$1"/xg; $s =~ s/("|})\s\K/,/g; $s =~ tr/{}/[]/; print Dumper fix_aref([ eval $s ]); sub fix_aref { my $aref = shift; ref and $_ = fix_aref($_) for @$aref; return $aref unless $#$aref % 2; for ( 0 .. $#$aref ) { next if $_ % 2; return $aref unless exists $valid_keys{ ${$aref}[$_] } } return +{ @$aref } } #### $VAR1 = [ 'sys', 'ecm', 'cloud-provider', '/Common/aws-ec2', { 'property-template' => { 'region' => { 'valid-values' => [ 'us-east-1', 'us-west-1' ] }, 'availability-zone' => { 'valid-values' => [ 'a', 'b', 'c', 'd' ] }, 'instance-type' => { 'valid-values' => [ 't2.micro', 't2.small', 't2.medium' ] }, 'account' => {} }, 'description' => 'The aws-ec2 parameters' } ];