CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Beginner:
undefined value as a symbol reference

 



imillard
Deleted

Jan 8, 2001, 9:19 AM

Post #1 of 6 (426 views)
undefined value as a symbol reference Can't Post

I keep getting an error from one of my filehandles. I am using: use strict and -w. The error i get is:

Error 1: Can't use an undefined value as a symbol reference at cgi-bin/rtf/parse_converted3.pl Line 541.

Here is the sub in question:

538 sub map {
539 my $mapfh = new FileHandle "../FIELD_MAP.csv";
540 my $map;
541 while ( <$mapfh> ) {
542 chomp $_;
543 my ($field,$cat,$ignore) = split(/,/,$_);
544 $map->{$field} = $cat;
545 }
546 undef $mapfh;
547 return $map;
548 }

Can anyone help?



kencl
User

Jan 9, 2001, 10:24 PM

Post #2 of 6 (415 views)
Re: undefined value as a symbol reference [In reply to] Can't Post

There's already a map function in PERL. Try this:

sub MapCSV { # I renamed the subroutine just in case the name itself was the problem
open(MAPFH, "<../FIELD_MAP.csv") or die $!;
my %Hash = map {split(/\,/, $_, 2)} <MAPFH>; # Limited the split to 2 so that the third field is ignored.
close(MAPFH);
return %Hash;
}

Please post a note if it works. This is my first time using the map function :)



rGeoffrey
User / Moderator

Jan 10, 2001, 2:56 PM

Post #3 of 6 (400 views)
Re: undefined value as a symbol reference [In reply to] Can't Post

Your use of map is good, but the use of the third argument of split is not. Consider this block of code...


Code
my @lines = ("fred,wilma,from the town of bedrock", 
"george,jane,works for spacely sprockets",
"homer,marge,sings in the key of springfield");

my %hash = &MapCSV2 (@lines);

foreach my $key (keys (%hash)) {
print "==$key==$hash{$key}==\n";
}


sub MapCSV2
{
my %Hash = map {split(/\,/, $_, 2)} @_;
return %Hash;
}

I have simplified the function to just read an array from @_ and avoid the file because it makes testing easier and file handling is not the point of this exercise.

Here is the output from the %hash...


Code
==fred==wilma,from the town of bedrock== 
==george==jane,works for spacely sprockets==
==homer==marge,sings in the key of springfield==

Becuase we told split to make exactly 2 parts, perl will split on the first comma, and everything after it is now the second part. So the second part has the wife, which we wanted, and all the other words that we did not.

Change the split from 2 to 3

If you change to this...

Code
sub MapCSV2 
{
my %Hash = map {split(/\,/, $_, 3)} @_;
return %Hash;
}

The output will look like this...


Code
==fred==wilma== 
==from the town of bedrock==george==
==jane==works for spacely sprockets==
==homer==marge==
==sings in the key of springfield====

Notice that this time we are getting the string split into husband, wife, and words. But then map makes an array of 9 elements to pass on to the hash. The hash takes them as pairs so 'george' is now the value to a key from the previous line. And the final spot is blank because we had an odd number of array elements.

Try an array slice to get just the two parts we want


Code
sub MapCSV2 
{
my %Hash = map { (split(/\,/, $_, 3))[0,1] } @_;
return %Hash;
}

Output is...


Code
==fred==wilma== 
==george==jane==
==homer==marge==

This time we add an array slice (@the array from split)[0,1] and get the right answer.

Use a regular expression to get the parts


Code
sub MapCSV2 
{
my %Hash = map { $_ =~ m/(.*?),(.*?),/ } @_;
return %Hash;
}

Output is...


Code
==fred==wilma== 
==george==jane==
==homer==marge==

For each line of data we match the stuff before the first and second commas and then the two found things inside the parentheses are passed out the the map. And they live in $1 and $2, but that is not important right now. Not knowing anything about the data I did .*? which is one of the more expensive matches, but will do exactly what we want. If you know that the data will be exactly one word you could switch to \w+ and get some boost in performance.

So as with most other things, "There is more than one way to do it". But the split version is probably better for this problem.

Just remember when you do a map to fill a hash that you should send an even number of elements or strange things could happen. And then you too can believe that map is the coolest feature in perl.



Sun Sep 9, 2001 - 1:46:40 GMT, a very special second in the epoch.


kencl
User

Jan 17, 2001, 6:53 PM

Post #4 of 6 (384 views)
Re: undefined value as a symbol reference [In reply to] Can't Post

Thanks for explaining that. I had misunderstood how limiting a split works.

Something else has come up though, and that is, how do I get rid of trailing newline characters during a map function? Neither of these seem to work:

%Config = map {split(/\,/, chomp($_))} <CONFIG>;

%Config = map {split(/\,/, $_)} chomp(<CONFIG>);

Thanks.



japhy
Enthusiast

Jan 18, 2001, 6:41 AM

Post #5 of 6 (372 views)
Re: undefined value as a symbol reference [In reply to] Can't Post

The main problem you are facing is that chomp() does not return the string, but rather a number saying how many strings it chomp()ed.

In your case, I would call the function on the entire hash:


Code
chomp( %config = map split(/,/), <CONFIG> );

Or, to avoid reading all the file at once, I might do:


Code
while (<CONFIG>) { 
chomp;
my ($k,$v) = split /,/;
$config{$k} = $v;
}

But that might be a little too long-winded and not idiomatic enough for you.

Jeff "japhy" Pinyan -- accomplished hacker, teacher, lecturer, and author


kencl
User

Jan 18, 2001, 8:24 PM

Post #6 of 6 (366 views)
Re: undefined value as a symbol reference [In reply to] Can't Post

DOH! I knew that too :(

Anyway, here's what I ended up doing, for the benefit of others:


Code
open(CONFIG, "<mlconfig.txt") or die $!; 
%Config = map {split(/\,/, $_)} <CONFIG>;
close(CONFIG);
foreach $key (keys %Config) {
chomp($Config{$key});
}

Sometimes I wonder if I'll ever get beyond the beginner section...


 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives