1

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
}
11
  • 1
    The posted code is incorrect Perl, which can't run (even if it were complete) and won't produce what code comments show. Can you post your actual code? That helps a lot in helping you out. Commented Oct 2, 2018 at 19:46
  • Also I'm unclear whether you're wanting to do a pattern match against the names of the files in @files, or do you want to open the files, read lines of data from them and match against those lines? It would be helpful if you could provide examples of the filenames if that's what you're matching, or examples of file contents. Commented Oct 2, 2018 at 19:50
  • @zdim Code was edited/updated... any help would be greatly appreciated Commented Oct 2, 2018 at 19:51
  • @GrantMcLean I just want to be able to put the four string values from the string ($name) into a seperate hash key values. I updated the code for the filename. It is globbed so it has multiple values... Commented Oct 2, 2018 at 19:52
  • To break the string 'G43B76P90T45' into "letter-numbers" patterns (the goal I assume from the question): my @parts = 'G43B76P90T45' =~ /([a-zA-Z][0-9]+)/g; But the code shown in the question is "Illegal" with many basic syntax errors and I can't tell whether the above will actually work in your real code. Just once more: please show us your actual code :) Commented Oct 2, 2018 at 19:57

2 Answers 2

1

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"};
Sign up to request clarification or add additional context in comments.

2 Comments

This assumes that patterns to extract are always three characters long; I'd state that assumption. (Also, to nitpick: it does "print the hash", it prints one element of it.)
Simplifies to: my %hash; @hash{qw( first second third fourth )} = unpack('(A3)*', $name);
1

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.

1 Comment

I used (...) as a simple way to match any 3 characters. But yes, you could also write it as (.{3}) or ([a-zA-Z0-9]{3}) or even (\w{3}) which is letters, number and the _ underscore (i.e.: characters that are valid in a Perl variable/identifier name).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.