use strict; use warnings; use Data::Dumper; my %properties; while (my $propline = ) { next if $propline =~ /^#/; chomp $propline; my ($key, $value) = split(/=/, $propline, 2); _insert(\%properties, $key, $value); } sub _insert { my ($root, $key, $value) = @_; my ($first, $rest) = split /\./, $key, 2; if (defined $rest) { $root->{$first} = {} unless ref($root->{$first}) eq 'HASH'; _insert($root->{$first}, $rest, $value); } else { $root->{$first} = $value; } } print Dumper(\%properties); __DATA__ #### language_id.en_US=-1 language_id.es_US=-11 language_id.en_CA=-12 language_id.fr_CA=-13 langid.SPMEX=es_US langid.FRCAN=fr_CA altlang.US=SPMEX altlang.CA=FRCAN itemattr.newpart.seq=1 itemattr.newpart.name=New Part itemattr.newpart.image1.en_US=newitem_icon.gif itemattr.newpart.image1.es_US=newitem_icon_sp.gif itemattr.newpart.image1.en_CA=newitem_icon.gif itemattr.newpart.image1.fr_CA=newitem_icon_fr.gif itemattr.watersaver.seq=2 itemattr.watersaver.name=New Part itemattr.watersaver.image1.en_US=newitem_icon.gif itemattr.watersaver.image1.es_US=newitem_icon_sp.gif itemattr.watersaver.image1.en_CA=newitem_icon.gif itemattr.watersaver.image1.fr_CA=newitem_icon_fr.gif