jonc has asked for the wisdom of the Perl Monks concerning the following question:

Hello PerlMonks! I'm new here, and am a beginner programmer (Perl is first language). Let me know if this post is up to code (haha...sorry)

As shown in subject, I am getting that error(see comment ERROR HERE at last line of code) when I run the code below. It is fixed if I uncomment the if(defined $item).

However, I think it is better to fix the problem instead of ignoring it. It prints "chpt31_4" four times and then gives the error message. Hopefully you can help debug this or better, explain it:

Here is the code:

#!/usr/bin/perl use strict; use warnings FATAL => "all"; #use diagnostics; require 'verbTenseChanger.pl'; ## -JUST FOR TESTING- ## my $chapter_section = "chpt"."31_4"; my $search_key = "move"; my $category_id = "all"; # --- Files --- # open(my $parse_corpus, '<', "parsed${chapter_section}.txt") or die $!; # --- Different forms of the Searchword --- # my @temp_changeverbforms = map changeVerbForm( $search_key, 0, $_ ), 1 +..4; my @verbforms; push (@verbforms, $search_key);# Watch extra for loop foreach my $temp_changeverbforms (@temp_changeverbforms) { push (@verbforms, $temp_changeverbforms) unless ($temp_changeverbf +orms eq ""); } # --- Variables for Searching/working with parser and tagger --- # my @lines = <$parse_corpus>; my $chapternumber_value; my $sentencenumber_value; my @all_matches; my $sentence; my $grammar_relation; my $argument1; my $argument2; foreach my $line (@lines) { print "$line\n\n"; ##TEST ONLY## foreach my $verbform (@verbforms) { my $one_match_ref = []; #Chpt. num (Could check %seens): if ($line =~ /^Parsing file: (chpt\d+_\d+).txt/) { $one_match_ref->[0] = $1 ; ##Only once in file } if ($line =~ /\b$verbform\b/i) { #Sent. num: #SentSentences: if ($line =~ /^Parsing \[(sent. \d+) len. \d+\]: \[(.+)\] +/) { $one_match_ref->[1] = $1; ##Multiple in file $one_match_ref->[2] = $2; $one_match_ref->[2] =~ s/,//g; } #Dependencies: if ($category_id eq "all") { if ($line =~ /subj\w*\(|obj\w*\(|prep\w*\(|xcomp\w*\(| +agent\w*\(|purpcl\w*\(|conj_and\w*\(/) { if ($line =~ /(\w+)\((\w+)\-\d+\,\s(\w+)\-\d+\)/) +{ $one_match_ref->[3] = $1; $one_match_ref->[4] = $2; $one_match_ref->[5] = $3; } } } } # add the reference of match into array. push (@all_matches, $one_match_ref); } } # walk through all the matches. foreach my $array_ref (@all_matches) { foreach my $item (@{$array_ref}) { print "$item\n";# if (defined($item)); ##ERROR HERE!!!! } }

I also have an 'array of hash' version, if it would be better. Hopefully the fix can be used there as well

Not sure if this is needed, but here is the format of the file being passed in:

Parsing [sent. 34 len. 34]: [The, form, of, its, skeleton, and, body, cavities, strongly, influences, the, degree, to, which, an, animal, can, control, and, change, its, shape, ,, and, thus, the, complexity, of, the, movements, it, can, perform, .]
nsubj(evolved-12, animals-11)
ccomp(suggests-9, evolved-12)
prep_from(evolved-12, colonies-14)

The purpose of this code is to search the file for chapternumber(ie. chpt31_4, sentence number(ie. sent. 34), sentence itself, grammar relation (ie. nsubj), arg1 (ie. evolved) and arg2 (ie. animals).

I get all these elements into an array, and they constitute 1 match. I need an array of all these match arrays

Replies are listed 'Best First'.
Re: Error: Use of uninitialized value $item in concatenation (.) or string at...
by jethro (Monsignor) on Jun 10, 2011 at 16:45 UTC

    For every match your are setting array index 0 in one if-clause, index 1 and 2 in another if-clause and index 3,4 and 5 in a third if-clause. Now if for example the first if-clause doesn't match, index 0 will be undef, but the other indexes will have data in it. Same for the second if-clause.

    The solution depends on what your script does

    if every match needs all 6 data items to be there, you have to restructure your code. If the first 'if' succeeds, any following 'if' should be inside that if and not matching should result in an error message (or in refuting that match)

    If incomplete data in a match is normal you could either just use your "if defined" solution or push data onto your array instead of setting it. i.e.

    #instead of $one_match_ref->[3] = $1; $one_match_ref->[4] = $2; $one_match_ref->[5] = $3; #use push( @{one_match_ref},$1,$2,$3 );

    That way no holes are generated in your arrays

      Amazing! You're definitely right... I think I have to restructure, all the elements have to stay together. But the all-encompassing if-clauses won't help until I make each sent. number and it's sentence and all the grammar functions one large string...

      But if I were to use the push method, the same error persists if I don't put defined??:
      foreach my $line (@lines) { print "$line\n\n"; ##TEST ONLY## foreach my $verbform (@verbforms) { my $one_match_ref = []; #Chpt. num (Could check %seens): if ($line =~ /^Parsing file: (chpt\d+_\d+).txt/) { #$one_match_ref->[0] = $1 ; ##Only once in file push( @{$one_match_ref}, $1 ); } if ($line =~ /\b$verbform\b/i) { #Sent. num: #SentSentences: if ($line =~ /^Parsing \[(sent. \d+) len. \d+\]: \[(.+)\] +/) { #$one_match_ref->[1] = $1; ##Multiple in file #$one_match_ref->[2] = $2; #$one_match_ref->[2] =~ s/,//g; my $nocomma_sent = $2; $nocomma_sent =~ s/,//g; push( @{$one_match_ref}, $1, $nocomma_sent); } #Dependencies: if ($category_id eq "all") { if ($line =~ /subj\w*\(|obj\w*\(|prep\w*\(|xcomp\w*\(| +agent\w*\(|purpcl\w*\(|conj_and\w*\(/) { if ($line =~ /(\w+)\((\w+)\-\d+\,\s(\w+)\-\d+\)/) +{ #$one_match_ref->[3] = $1; #$one_match_ref->[4] = $2; #$one_match_ref->[5] = $3; push( @{$one_match_ref}, $1, $2, $3 ); } } } } # add the reference of match into array. push (@all_matches, $one_match_ref); } }

        You might find Data::Dumper helpful. Try adding the following to the end of your script:

        use Data::Dumper; # you could put this at start of script print Dumper(\@all_matches);

        This will print your data structure in a fairly easy to understand format (see the documentation for details). It might help you to find and understand what is undefined.

        if ($line =~ /^Parsing \[(sent. \d+) len. \d+\]: \[(.+)\] +/) { #$one_match_ref->[1] = $1; ##Multiple in file #$one_match_ref->[2] = $2; #$one_match_ref->[2] =~ s/,//g; my $nocomma_sent = $2; $nocomma_sent =~ s/,//g; push( @{$one_match_ref}, $1, $nocomma_sent); }

        This might be the source of one of your uninitialized values.

        See perlre for details of the match variables ($1, $2, etc.). The important thing here is that these variables are reset by the next successful match. If your substitution to remove commas finds any, then it is a successful match, after which $1 and $2 are reset to undef. Thus, if $nocomma_sent has any commas in it, when you push $1 onto your array you will be pushing undef.

        One way to avoid this is to push $1 before performing the substituion:

        if ($line =~ /^Parsing \[(sent. \d+) len. \d+\]: \[(.+)\] +/) { push( @{$one_match_ref}, $1); my $nocomma_sent = $2; $nocomma_sent =~ s/,//g; push( @{$one_match_ref}, $nocomma_sent); }