use strict; use warnings; my @lines = ( '012345 NA13333 C C', '012345 NA13334 F F', '012345 NA13335 E F', '012346 NA13333 U U', '012346 NA13334 I I', '012346 NA13335 Y O'); foreach my $line (@lines) { next unless $line =~ m{^(\S+) NA(\d+) (.*)}; my ($site, $userID, $data) = ($1, $2, $3); print "SITE: $site USER: $userID DATA: $data\n"; } #### SITE: 012345 USER: 13333 DATA: C C SITE: 012345 USER: 13334 DATA: F F SITE: 012345 USER: 13335 DATA: E F SITE: 012346 USER: 13333 DATA: U U SITE: 012346 USER: 13334 DATA: I I SITE: 012346 USER: 13335 DATA: Y O #### next unless $line =~ m{^(\S+) (\d+) (.*)}; my ($site, $userID, $data, $data2) = ($1, $2, $3, $4); # you have 3 capturing paran's but you try to call $4 # your 2 data columns get folded together in $3 because of your greedy .* $user{$userID}{$site} = $data, $data2; # $data2 is useless and I think you are trying to use an array ref # but that is not what you are doing [ ] signifies an array ref #### print Dumper \%user;