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). | [reply] [Watch: Dir/Any] [d/l] [select] |
#!/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};
| [reply] [Watch: Dir/Any] [d/l] [select] |
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.
| [reply] [Watch: Dir/Any] [d/l] [select] |
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.
| [reply] [Watch: Dir/Any] [d/l] [select] |
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. | [reply] [Watch: Dir/Any] [d/l] |
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.
| [reply] [Watch: Dir/Any] [d/l] [select] |
Thanks, Always learning.
John
| [reply] [Watch: Dir/Any] |