Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Help to identify Error in my program

by ashnator (Sexton)
on Oct 21, 2008 at 02:49 UTC ( [id://718360]=perlquestion: print w/replies, xml ) Need Help??

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

Dear Monks, I have 2 files:- 1) File 1 with format John 10 Andrew 16 Mathew 27 2) File 2 with format >John 40 34 40 40 40 40 40 40 40 50 40 40 40 40 40 40 40 20 40 40 40 30 40 4 +0 40 40 40 40 37 40 40 40 40 40 25 40 >Andrew 40 40 44 40 40 40 40 50 40 40 40 40 50 40 40 14 40 40 6 40 40 45 40 40 + 40 40 40 40 40 40 29 40 40 40 6 40 >Mathew 40 40 40 40 39 40 40 40 40 40 40 40 35 40 40 40 40 40 40 40 40 27 40 4 +0 40 40 40 40 33 40 40 40 40 4 40 40 I am parsing File 2 with File 1 values as hash. Now I pa +rse it like this. John in File 1 has a value of 10. So I parse File 2 + and check John Record at 10th position if the value is >= 20. If yes + then I print my results as: 3) Result File John 10 50 Now the problem is that I am getting the following error:- Use of uninitialized value in subtraction (-) at validator.pl line 24, + <FD> chunk 2. Use of uninitialized value in concatenation (.) or string at validator +.pl line 26, <FD> chunk 2. Here is My code:- #!/usr/bin/perl -w my %hashtable; my $fn = <>; ##### File 1 is the input. open(FH, "$fn") || die "Cannot open file"; while (<FH>) { chomp($_); $hashtable{$1} = $2 if $_ =~ /(\S+)\s+(\S+)/; } while (my ($key, $value) = each(%hashtable)) { #print $key. ", ". $value."\n"; } open(FD,"<File2.txt") || die("Can't open: $!"); $/ = '>'; while ( <FD> ) { chomp; next if ! s{ \A (\S+) \s+ (?= \d ) }{}xms; my $name = $1; my @numbers = split /\D+/; my $one_number = $numbers[$hashtable{$name} - 1]; ### Error warnin +g in this line if ( $one_number >= 20 ) { print "$name $hashtable{$name} $one_number\n"; ### Error warn +ing in this line } } Can you please help me to identify the Error !! Thanks

Replies are listed 'Best First'.
Re: Help to identify Error in my program
by graff (Chancellor) on Oct 21, 2008 at 03:14 UTC
    Please read some of the links that are provided below the text entry box when you are composing a post; learn to use the "code tags" (<code> or <c>), placing them only around your code snippets, not around your entire post. Please do not use <pre> tags at all.

    If you are going to present us with error messages that include line numbers, you should indicate in your code which lines those numbers represent. I'm guessing that the two messages you quoted -- which are actually warnings (not errors) -- refer to the two lines marked below:

    my $one_number = $numbers[$hashtable{$name} - 1]; # line 24 if ( $one_number >= 20 ) { print "$name $hashtable{$name} $one_number\n"; # line 26 }
    This would suggest that those messages resulted from an iteration of your while <FD> loop in which the variable "$name" was set to a value that happened to be non-existent as a key in "%hashtable". If you change your test condition from this:
    next if ! s{ \A (\S+) \s+ (?= \d ) }{}xms;
    to something like this instead:
    next unless ( s{ \A (\S+) \s+ (?= \d ) }{}xms and exists( $hashtab +le{$1} ));
    then the warnings should go away (and you might end up with fewer lines of printed output).
    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Help to identify Error in my program
by blazar (Canon) on Oct 21, 2008 at 09:04 UTC
    #!/usr/bin/perl -w my %hashtable; my $fn = <>; ##### File 1 is the input. open(FH, "$fn") || die "Cannot open file";

    First, do a favour to yourself and use strict as well. Then, if you don't chomp $fn, it will end with "\n" and be unlikely albeit not impossible to be the real filename you're after. Last, $fn is called "useless use of quoting." Well, it's not really "last" because I may point out that you'd better use lexical filehandles, the three args form of open, low precedence short circuiting logical operators, include both the name of the file and more importantly the cause of the error ($!) in the error message, etc. But I'll try to stick to pointing out only the major issues...

    my $one_number = $numbers[$hashtable{$name} - 1]; ### Error warnin +g in this line if ( $one_number >= 20 ) { print "$name $hashtable{$name} $one_number\n"; ### Error warn +ing in this line

    Indeed: what if $name is not a key of $hashtable? Appearently you have one or more names in the second file that are missing from the former. Try finding out which ones they are. A simple

    say "<$name>" unless exists $hashtable{$name};

    would do: the additional < and > marks are there to be sure about "hidden" characters like spaces. But if you want to be really fussy you may even try:

    say map {my $_=$_; s/([^[:print:]])/sprintf '\\%03o', $1/ge; "<$_>"} $ +name unless exists $hashtable{$name};
    --
    If you can't understand the incipit, then please check the IPB Campaign.
      I don't understand why they used <>. This returns the first line of the first file passed. Not the first argument on the command line.
      You're right they'd have to chomp it if the filenames were listed at the start of each file but seeing as I don't think they meant that. shift of the @ARGV array is fine and wouldn't need chomping.

        I personally believe that he's not passing any file on the command line, (the other filename is hardcoded some lines below...) in which case it will read the first line from STDIN, but certainly, if he wanted to rely on this behaviour then he should have used <STDIN>. Just one out of many gotchas in a lump of bad code.

        --
        If you can't understand the incipit, then please check the IPB Campaign.
Re: Help to identify Error in my program
by binf-jw (Monk) on Oct 21, 2008 at 09:31 UTC
    As people have said is because your keys don't exists.
    I've neatened up your code a bit, to make it more readable.
    Some pointers:
    - use English: This lets you use $INPUT_RECORD_SEPARATOR instead of $\ or $/ I can't even remember which one, I only knew from your input file
    - use Data::Dumper: This lets you dump variables to see what's inside them
    - use lowercase keys (lc) this ensures case isn't an issue


    The output I get is:
    john 10 50
    mathew 27 40


    Code:
    #!/usr/bin/perl use warnings; use English q/-no_match_vars/; use strict; use Carp qw/croak carp/; use Data::Dumper; my $file_one_ref; my $file_one_fn = shift or croak "No input file specifed for file one" +; my $file_two_fn = shift or croak "No input file specifed for file two" +; open my $file_one_fh, '<', $file_one_fn or croak "Could not open filename [$file_one_fn] : ", $OS_ERROR; while (<$file_one_fh>) { $file_one_ref->{ lc $1 } = $2 if / \A (\w+) \s+ (\w+) /xms; } # You can do the above input like this but it's not as efficient: # map { $file_one_ref->{ lc $1 } = $2 if / (\w+) \s+ (\w+)/xms; } <$in +put_fh>; # Have a look at the keys read in: print Dumper($file_one_ref), "\n\n"; open my $file_two_fh, '<', $file_two_fn or croak "Could not open filename [$file_two_fn] : ", $OS_ERROR; $INPUT_RECORD_SEPARATOR = '>'; while ( my $line = <$file_two_fh> ) { # I reserve s{}{}xms; for multi line expressions next if ( $line !~ s/ \A (\S+) \s+ (?= \d ) //xms and !exists $fil +e_one_ref->{ lc $1 } ); # why not just use a match? is $name going to contain numbers my $name = lc $1; my $numbers = [ grep { $_ } split /\D+/, $line ]; my $one_number = $numbers->[ $file_one_ref->{$name} - 1 ] || next; if ( $one_number >= 20 ) { print join " ", $name, $file_one_ref->{$name}, $one_number, "\ +n"; } } close $file_one_fh or croak "Could not open filename [$file_one_fn] : ", $OS_ERROR; close $file_two_fh or croak "Could not open filename [$file_two_fn] : ", $OS_ERROR; __END__
    Update: See below.

      If you're going to use English and aren't actually using the verbose forms of $& and friends it's better to use English '-no_match_vars'; instead so as not to slow down every regex match your program does (presuming a post 5.8 perl; before that there's not a way to dodge the slowdown bullet).

      (But really, bite the bullet and learn which is which; or just remember: perldoc perlvar is my friend.)

      The cake is a lie.
      The cake is a lie.
      The cake is a lie.

        Thanks, Always learning.
        John

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://718360]
Approved by graff
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (5)
As of 2024-03-29 10:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found