I am trying to compare if two inputs ($name, $place) match the respective key and value of a hash. So, if $name matches a key and $place matches that key's value, "Correct" is printed. My code unfortunately is incorrect. Any suggestions? Thanks!
use 5.010;
use strict;
use warnings;
my ($name, $place, %hash, %hash2);
%hash = (
Dominic => 'Melbourne',
Stella => 'Beijing',
Alex => 'Oakland',
);
%hash2 = reverse %hash;
print "Enter name: ";
$name = <STDIN>;
print "Enter place: ";
$place = <STDIN>;
chomp ($name, $place);
if ($name eq $hash{$name} && $place eq $hash2{$place}) {
print "Correct!\n";
} else {
print "NO!\n";
}
While a lot may be done to correct this (unrelated to the question), but here is the minimal solution necessary:
use 5.010;
use strict;
use warnings;
my %hash = (
Dominic => 'Melbourne',
Stella => 'Beijing',
Alex => 'Oakland',
);
print "Enter name: ";
my $name = <STDIN>;
print "Enter place: ";
my $place = <STDIN>;
if ($name and $place) {
chomp ($name, $place);
if (exists($hash{$name}) and ($place eq $hash{$name})) {
print "Correct!\n";
} else {
print "NO!\n";
}
} else {
print "ERROR: Both name and place required to make this work!";
}
As you are reading from STDIN you need to sanity check the input otherwise you get these problems in your result (not to mention the "Correct!" at the end) with unexpected input:
Enter name:
Enter place:
Use of uninitialized value $name in chomp at original.pl line 19.
Use of uninitialized value $place in chomp at original.pl line 19.
Use of uninitialized value $name in hash element at original.pl line 22.
Use of uninitialized value $name in string eq at original.pl line 22.
Use of uninitialized value in string eq at original.pl line 22.
Use of uninitialized value $place in hash element at original.pl line 22.
Use of uninitialized value $place in string eq at original.pl line 22.
Use of uninitialized value in string eq at original.pl line 22.
Correct!
Instead of this that should be generated with error checked code:
Enter name:
Enter place:
ERROR: Both name and place required to make this work!
PS: Please bear with my variable declaration changes, it's just OCD from me, unrelated to the question at hand. Like I said a lot could be done.
Related
I came across an interesting problem with following piece of code in perl 5.22.1 and perl 5.30.0
use strict;
use warnings;
use feature 'say';
#use Data::Dumper;
my %hash;
my %seen;
my #header = split ',', <DATA>;
chomp #header;
while(<DATA>) {
next if /^\s*$/;
chomp;
my %data;
#data{#header} = split ',';
push #{$hash{person}}, \%data;
push #{$hash{Position}{$data{Position}}}, "$data{First} $data{Last}";
if( ! $seen{$data{Position}} ) {
$seen{$data{Position}} = 1;
push #{$hash{Role}}, $data{Position};
}
}
#say Dumper($hash{Position});
my $count = 0;
for my $person ( #{$hash{person}} ) {
say "Person: $count";
say "Role: $person->{Position}";
}
say "---- Groups ----\n";
while( my($p,$m) = each %{$hash{Position}} ) {
say "-> $p";
my $members = join(',',#{$m});
say "-> Members: $members\n";
}
say "---- Roles ----";
say '-> ' . join(', ',#{$hash{Role}});
__DATA__
First,Last,Position
John,Doe,Developer
Mary,Fox,Manager
Anna,Gulaby,Developer
If the code run as it is -- everything works fine
Now it is sufficient to add $count++ increment as bellow and code produces errors
my $count = 0;
for my $person ( #{$hash{person}} ) {
$count++;
say "Person: $count";
say "Role: $person->{Position}";
}
Errors:
Error(s), warning(s):
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 22, <DATA> line 2.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 23, <DATA> line 2.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 24, <DATA> line 2.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 22, <DATA> line 3.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 23, <DATA> line 3.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 22, <DATA> line 4.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 23, <DATA> line 4.
Use of uninitialized value in concatenation (.) or string at source_file.pl line 35, <DATA> line 4.
Use of uninitialized value in concatenation (.) or string at source_file.pl line 35, <DATA> line 4.
Use of uninitialized value in concatenation (.) or string at source_file.pl line 35, <DATA> line 4.
Use of uninitialized value in join or string at source_file.pl line 48, <DATA> line 4.
This problem does not manifest itself in perl 5.30.0 (Windows 10, Strawberry Perl) or Perl v5.24.2.
Note: the problem manifests itself not only with $count++ but with any other access to content of the hash next to say "Person: $count"; -- post# 60653651
I would like to hear comments on this situation, what is the cause?
CAUSE: input data have eol in DOS form \r\n and when data processed in Linux chomp removes only \n leaving \r as part of the field name (used as hash key). Thanks goes to Shawn for pointing out the source of the issue.
SOLUTION: universal fix was implemented in form of snip_eol($arg) subroutine
use strict;
use warnings;
use feature 'say';
my $debug = 0;
say "
Perl: $^V
OS: $^O
-------------------
" if $debug;
my %hash;
my %seen;
my #header = split ',', <DATA>;
$header[2] = snip_eol($header[2]); # problem fix
while(<DATA>) {
next if /^\s*$/;
my $line = snip_eol($_); # problem fix
my %data;
#data{#header} = split ',',$line;
push #{$hash{person}}, \%data;
push #{$hash{Position}{$data{Position}}}, "$data{First} $data{Last}";
if( ! $seen{$data{Position}} ) {
$seen{$data{Position}} = 1;
push #{$hash{Role}}, $data{Position};
}
}
#say Dumper($hash{Position});
my $count = 0;
for my $person ( #{$hash{person}} ) {
$count++;
say "-> Name: $person->{First} $person->{Last}";
say "-> Role: $person->{Position}\n";
}
say "---- Groups ----\n";
while( my($p,$m) = each %{$hash{Position}} ) {
say "-> $p";
my $members = join(',',#{$m});
say "-> Members: $members\n";
}
say "---- Roles ----";
say '-> ' . join(', ',#{$hash{Role}});
sub snip_eol {
my $data = shift; # problem fix
#map{ say "$_ => " . ord } split '', $data if $debug;
$data =~ s/\r// if $^O eq 'linux';
chomp $data;
#map{ say "$_ => " . ord } split '', $data if $debug;
return $data;
}
__DATA__
First,Last,Position
John,Doe,Developer
Mary,Fox,Manager
Anna,Gulaby,Developer
I can replicate this behavior by (On linux) first converting the source file to have Windows-style \r\n line endings and then trying to run it. I thus suspect that in your testing of various versions you're using Windows sometimes, and a Linux/Unix other times, and not converting the file's line endings appropriately.
#chomp only removes a newline character (Well, the current value of $/ to be pedantic), so when used on a string with a Windows style line ending in it, it leaves the carriage return. The hash key is not "Position", it's "Position\r", which is not what the rest of your code uses.
I am getting the following error when I try to execute my CGI script from the terminal:
Use of uninitialized value $friends{"Bob=416-333-6363"} in print at ./new-cgi/data.cgi line 24
Here is my script:
#!/usr/bin/perl -w
use strict;
my %friends;
my $name;
my $phone;
open FILE, "new-cgi/data.dat" or die ("No File\n");
while (<FILE>) {
chomp;
($name, $phone) = split(" ", $_);
$friends{$name}=$phone;
}
foreach (keys %friends) {
print "Name:", $_, "\n";
print "Phone:", $friends{$_}, "\n"; <--This is line 24
}
Hard to see without seeing your new-cgi/data.dat file, but I assume that the data format is a bunch of lines like "Bob=416-333-6363" in which case you want to split on /=/ not " ".
What's happening now is that you're splitting on a non-existant whitespace so $name (the eventual key) gets the entire line and $phone the eventual value, gets an undef value. So when you iterate over the hash later, you have a hash with lots of keys (albeit with odd data for the keys) and undef values.
use strict;
use warnings;
my $last_variable2= 'abc';
print "last var2 $last_variable2\n";
my #grouped;
while (<DATA>) {
my ($variable1,
$variable2,
$other_data) = split ',',$_,3;
if($variable2 ne 'abc'){
if( $variable2 ne $last_variable2){
print "\n\n";
print "'$variable2' doesn't equal '$last_variable2'\n";
my %HoA;
&process_data(#grouped_series);
#grouped = ();
}
}else{
print "Skipped this because it's the first\n";
}
push #grouped_series, $_;
$last_variable2 = $variable2;
}
When I run this code, I keep getting
Use of uninitialized value $last_variable2 in string ne at 1_1_correspondencer.pl line 32, <DATA> line 3.
Use of uninitialized value $variable2 in string ne at 1_1_correspondencer.pl line 33, <DATA> line 3.
Use of uninitialized value $last_variable2 in concatenation (.) or string at 1_1_correspondencer.pl line 36, <DATA> line 6.
But, I initialized both variables. Sorry, this is a naive question--I only just started using strict and warnings
When parsing your DATA, you don't verify that each of these variables is defined:
my ($variable1,
$variable2,
$other_data) = split ',',$_,3;
If there are no commas on a row, then $variable2 would be undefined which is later assigned to $last_variable2. Maybe add some data verification to take into account that case?
if (! defined $variable2) {
warn "missing variable2 definition: $_\n";
}
Without seeing your actual data, we can't really advise you more.
I have a tab-delimited file: abc.txt.
which has data like:
Pytul_T015270 Protein of unknown function
Pytul_T015269 Protein of unknown function
Pytul_T015255 Protein of unknown function
Pytul_T015297 Protein of unknown function
I am creating a parser which takes this abc.txt and 2 other files as input and parses the files by calling different subroutines from a package: utility.pm
The subroutine to parse abc.txt is defined in my package, utility.pm goes as follows:
use strict;
sub readblast{
my $fileName = shift;
my %hash;
my %geneNameHash;
open PRED, $fileName or die "Can't open file $!\n";
while (my $line=<PRED>) {
chomp $line;
#print $line,"\n";
(my $gene,my $desc) = split /\t/, $line;
$hash{$gene} = $desc;
}
close(PRED);
return %hash;
}
And my parser.pl script, which uses the hash is as follows:
my %blast=&utility::readblast($ARGV[2]);
for my $mRNA(keys %{ $featureHash{$scaffold}{$gene}}){
my $desc = $blast{$mRNA};
}
Here $featurehash is another hash I made from another file. And $mRNA has the key values of the file abc.txt.
But output of $desc is blank and I am getting error:
Use of uninitialized value $desc in concatenation (.) or string at parser.pl
What is wrong with my $desc = $blast{$mRNA}; And why won't it store the 2nd column of abc.txt?
The following guards against trailing blank lines and possible non-tab separators (by using split with a limit):
#!/usr/bin/env perl
package My::Utility;
use strict;
use warnings;
sub read_blast {
my $fh = shift;
my %hash;
while (my $line = <$fh>) {
chomp $line;
last unless $line =~ /\S/;
my ($key, $value) = split ' ', $line, 2;
$hash{ $key } = $value;
}
return \%hash;
}
package main;
my $blast = My::Utility::read_blast(\*DATA);
while (my ($k, $v) = each %$blast) {
print "'$k' => '$v'\n";
}
__DATA__
Pytul_T015270 Protein of unknown function
Pytul_T015269 Protein of unknown function
Pytul_T015255 Protein of unknown function
Pytul_T015297 Protein of unknown function
I would like to change variables stored in a hash, but I kept receiving the error:
"Can't use the string ("SCALAR(0x30f558)") as a SCALAR ref while "strict refs" in use at - line 14.
My simplified code is as follows:
#!/usr/bin/perl
use strict;
use warnings;
my $num = 1234;
my $a = 5;
my %hash = (\$num => "value");
foreach my $key (keys %{hash}){
print "Key: $key\n";
#OPTION1: $a = $$key;
}
my $ref = \$num ;
print "Ref: $ref\n";
#OPTION2: $a = $$ref ;
print $a;
Running this prints:
Key: SCALAR(0x30f558)
Ref: SCALAR(0x30f558)
5
showing that both $key and $ref are pointing to the same variable - $num
Also, the code on OPTION1 and OPTION2 are identical if $key and $ref are the same.
When I uncomment OPTION2, $a prints out as 1234.
When I uncomment OPTION1, however, I receive the error shown above.
QUESTION:
How do I change $a to $num using the hash as I tried to do in OPTION1? And why will this not work as is?
References:
http://cpansearch.perl.org/src/CHIPS/perl5.004_05/t/pragma/strict-refs
I followed this code closely:
use strict 'refs' ;
my $fred ;
my $b = \$fred ;
my $a = $$b ;
which posed no error until I introduced the hash.
Thank you for your help.
Original Code (doesn't work):
#User Defined - here are the defaults
my $a = 122160;
my $b = 122351;
my $c = 'string';
my $d = 15;
my $e = 123528;
#etc.
#Create variable/print statement hash
my %UserVariables = (
\$a => "A: (Default: $a): ",
\$b => "B: (Default: $b): ",
\$c => "C: (Default: $c): ",
\$d => "D: (Default: $d): ",
\$e => "E: (Default: $e): ",
);
#Allow user to change variables if desired
foreach (keys %UserVariables){
print $UserVariables{$_};
chomp (my $temp = <>);
print "$_\n";
$$_ = $temp unless ($temp eq '');
print "$temp\n" unless ($temp eq '');
};
Less efficient method that does work:
#Alternate Method without loops (not ideal)
my $temp;
print $UserVariables{\$a};
chomp ($temp = (<>));
$a= $temp unless ($temp eq '');
print $UserVariables{\$b};
chomp ($temp = (<>));
$b= $temp unless ($temp eq '');
print $UserVariables{\$c};
chomp ($temp = (<>));
$c= $temp unless ($temp eq '');
print $UserVariables{\$d};
chomp ($temp = (<>));
$d= $temp unless ($temp eq '');
print $UserVariables{\$e};
chomp ($temp = (<>));
$e= $temp unless ($temp eq '');
Perl hash keys can only be string. You don't have reference as key, but what your reference automatically stringified to: a verbatim string "SCALAR(0x30f558)" instead. Obviously, string won't work as reference.
You should rethink the way you store data and maybe explain in little more details what you want to do instead on focusing on how.
In your particular case illustrated by example just use plain hash for those values you want to be overridable:
my %config = (
a => 122160,
b => 122351,
c => 'string',
d => 15,
e => 123528,
);
...and then overwrite values in this hash.
I would like to change variables stored in a hash
Just like you can't store variables in a scalar, you can't store variables in hashes. You can store values (including references to variables) in hashes. (Such as the string value in your code.)
showing that both $key and $ref are pointing to the same variable - $num
No. It shows that the values of $key and $ref have the same stringification.
When I uncomment OPTION1, however, I receive the error shown above.
Hash table keys are necessarily strings, just like array keys are necessarily non-negative integers.
I followed this code closely:
No, the same with hashes works fine.
use strict 'refs' ;
my %hash = ( fred => undef );
my $b = \$hash{fred} ;
my $a = $$b ;
I can't provide a solution, because you didn't say what you are trying to do.
You keep saying in the comments that you want to modify variables passed through STDIN, however it is not clear what you mean by this. Are you passing command line arguments or requesting input from the user or piping the output of another program into yours, or something else entirely? The ideal approach will vary slightly depending on what you're trying to do.
To read command line arguments you access the #ARGV array:
$foo = $ARGV[0]; #read the first argument
To read a line off of STDIN:
print "Enter a number: ";
$foo = <STDIN>;