JohnEgg
JohnEgg

Reputation: 59

How to convert string to hash table in perl

I have a string from a for loop:

@file = "/path/window/*_testing_42.csv";


foreach $file(@file) {


$name = $file=~ /(\w*)_testing_42/; #comes from file path
$name = 1$;
print $name; #prints G43B76P90T45

}

There are 4 values I am I need from this string (G43, B76, P90, T45). I want to place these into a hash so that I can refer to each value specifically. However the hash table code I am trying to implement is not working for my intended purpose:

 my %hash;



foreach $file(@file) {


    $name = $file=~ /(\w*)_testing_42/; #comes from file path
    $name = 1$;
    print $name; #prints G43B76P90T45



    my($first $second $third $fourth) = $name;
    $hash{"first"} = $first;
    $hash{"second"} = $second;
    $hash{"third"} = $third;
    $hash{"fourth"} = $fourth;

EXPECTED OUTPUT:

    print $fourth; #should print T45


    print $first; #should print G43
    print $third #should print  P90
}

Upvotes: 1

Views: 533

Answers (2)

Grant McLean
Grant McLean

Reputation: 6998

If I understand correctly what you're trying to do, then @Gever's answer should do the trick. Here's an alternative implementation using regexes rather than unpack:

use 5.010;
use strict;
use warnings;

my @file = glob("/path/window/*_testing_42.csv");

foreach my $file (@file) {
    my($name) = $file =~ /(\w+)_testing_42/;
    my @code = $name =~ /(...)/g;
    say 'Parts found: ', scalar(@code);   # Parts found: 4
    say $code[0];   # G43
    say $code[1];   # B76
    say $code[2];   # P90
    say $code[3];   # T45
}

I used an array rather than a hash, because that makes more sense to me, but if you really want a hash, you could do it like this:

foreach my $file (@file) {
    my($name) = $file =~ /(\w+)_testing_42/;
    my %hash;
    @hash{'first', 'second', 'third', 'fourth'} = $name =~ /(...)/g;
    say $hash{first};   # G43
    say $hash{second};  # B76
    say $hash{third};   # P90
    say $hash{fourth};  # T45
}

In this line:

my($name) = $file =~ /(\w+)_testing_42/;

The parentheses around $name are important because they force the match to be evaluated in list context, which returns the parts of the regex that were captured in the (\w+). Without the parentheses, the value 1 would be assigned to $name because there was 1 match.

The syntax for assigning a list of values to a series of keys in a hash (called a 'hash slice') is somewhat confusing. Perl knows we're assigning values into %hash because of the { after the variable name, but we put a @ before the variable name to indicate we're assigning multiple values to a hash slice. Using a $ before the variable name would indicate we're assigning to a single value in the hash.

The other thing I changed from your code is that I declared %hash inside the loop. Which means that you can only refer to it inside the loop. If you declare it outside the loop, one set of values will persist after each matching filename has been processed, but the hash might contain values from different filenames depending on how many fields were present on the last iterations.

Upvotes: 1

Gever
Gever

Reputation: 23

First you need to split the name in 4 parts:

my ($first, $second, $third, $fourth) = unpack("(A3)*", $name);

Fill the hash

$hash{"first"} = $first;
$hash{"second"} = $second;
$hash{"third"} = $third;
$hash{"fourth"} = $fourth;

and print the hash

print $hash{"fourth"};

Upvotes: 1

Related Questions