Perl, ne operator not working - perl

Can someone please tell me why my ne operator isn't working in the below if statement? It was working but after saving my program, it has stopped working. Any help would be greatly appreciated, cheers.
$inFile = "animals.txt";
open (IN, $inFile) or
die "Can't find file: $inFile";
#animallist = (<IN>);
foreach $line (#animallist)
{
if ($line =~ $search)
{
print "$line <br> <br>";
}
}
if ($line ne $search)
{
print "$search isn't in the animal list";
}
print end_html;

You seem confused about what your program does, so I thought I'd just tell you.
$inFile = "animals.txt";
open (IN, $inFile) or die "Can't find file: $inFile";
#animallist = (<IN>);
# here you define a file name, open a file, and read all of the lines
# in the file into the array #animallist
foreach $line (#animallist) {
# here you iterate over all the lines, putting each line into $line
if ($line =~ $search) {
print "$line <br> <br>";
}
# here you perform the regex match: $line =~ /$search/ and if it
# succeeds, print $line
}
# here you end the loop
if ($line ne $search) {
print "$search isn't in the animal list";
}
# here you take the now uninitialized variable $line and try to match
# it against the as of yet undefined variable $search
# If both of these variables are undefined, and you are not using warnings
# it will simply return false (because "" ne "" is false)
# without warning about undefined variables in ne
You should be aware that even if your entire line was, for example, cat, you still could not compare it using ne to the string cat, because when read from a file, it has a trailing newline, so it is really cat\n. Unless you chomp it.
It seems redundant to tell you, but of course you cannot check if the file does not contain $search after you finished reading the file. You have to do that while reading the file.

Try using indentation so you can see when your blocks end at inappropriate places.
if ($line ne $search) isn't even within the foreach loop where you are populating and handling $line from the file. I suggest putting it within the block to at least get the functionality I assume you are looking for.

It's hard to know what you expect to happen as we don't know what $search contains. Let's assume it's the name of an animal that is in your file.
When you execute your code, $search contains, say, "frog" and $line contains undef (as $line only contains data within your foreach loop). Those values aren't the same so the ne returns true and the message is printed.
If you were to move that if statement into the foreach block then $line would have a value. But it still wouldn't match as lines are read from a file with the newline character still attached. And "Frog" is not the same as "Frog\n". You need to use chomp() to remove the newline from $line.
This is very similar to another recent question. Are you working on the same piece of homework?

I think there are several points here:
For the if ($line ne $search), the $line is out of the scope of the foreach where it was declared and since you are not using strict, you won't get error and this condition should always be true.
I assume that $line has a newline so when you match this $line with $search, the condition can be true although the strings are not equal.
Assuming that $line = "lion\n" and $search = "lion"
then if you do if ($line =~ $search), the condition will be be true, because "lion" is part of the "lion\n" string. This means that:
if ($line eq $search) is false
and if ($line ne $search) is true which I assume is your case.
you can use the chomp($line) function to remove newlines from the end of the string.
I hope this helps.

Related

While loop will not find regex when checking for false value

I'm working on a script that gathers various specs of my companies computers, and stores it to a database. One section of the script searches through a file for the serial number of the credit card reader attached to the computer.
What I've found is that if I do not include a true/false check in the while condition, the regex will be matched, and I can break from there. That's fine, and it's what I'm going with. I do not understand though, why, when I change the while condition to include the true/false check, the regex is never matched.
Here is what I've found works
use v5.10;
use warnings;
use strict;
my $test;
open(my $fh, "<", "\\\\192.168.0.132\\storeman\\log\\2018-06-22.sls");
while(my $line = <$fh>){
if($line =~ /unitid/i){
$line =~ /(\d{3}\-\d{3}\-\d{3})/;
$test = $1;
last;
}
};
say $test // "Nothing found";
On the other hand though, the follow does not work.
use v5.10;
use warnings;
use strict;
my $test;
open(my $fh, "<", "\\\\192.168.0.132\\storeman\\log\\2018-06-22.sls");
while(my $line = <$fh> && !$test){
if($line =~ /unitid/i){
$line =~ /(\d{3}\-\d{3}\-\d{3})/;
$test = $1;
}
};
say $test // "Nothing found";
Note that in each case, $test is undeclared until the regex finds a match. Also, even when declaring $test as an empty string, and trying && $test ne "", the regex still never matches.
I've debugged to the best of my abilities, and all I know is that when using && !$test, the if($line =~ /unitid/i) is never found to be true.
What is it about the && !$test that could cause the regex to never match, and thus the loop to never break, but instead run through the whole file?
Consider the return of <$fh> && !$test - this is a boolean context. Perl will return the last evaluated statement - in this case !$test. Which, since $test is undefined, is true, so 1.
Thus, $line would now contain 1. Which doesn't match your regex :)
If you wanted to, you could write while( !$test && (my $line = <$fh>) ){,
which would then behave as you seemed to expect. You could even do
while( my $line = !$test && <$fh> ) - but I would not recommend that, as it is a bit confusing ( as you have noticed ;) ).

Perl script - Confusing error

When I run this code, I am purely trying to get all the lines containing the word "that" in them. Sounds easy enough. But when I run it, I get a list of matches that contain the word "that" but only at the end of the line. I don't know why it's coming out like this and I have been going crazy trying to solve it. I am currently getting an output of 268 total matches, and the output I need is only 13. Please advise!
#!/usr/bin/perl -w
#Usage: conc.shift.pl textfile word
open (FH, "$ARGV[0]") || die "cannot open";
#array = (1,2,3,4,5);
$count = 0;
while($line = <FH>) {
chomp $line;
shift #array;
push(#array, $line);
$count++;
if ($line =~ /that/)
{
$output = join(" ",#array);
print "$output \n";
}
}
print "Total matches: $count\n";
Don't you want to increment your $count variable only if the line contains "that", i.e.:
if ($line =~ /that/) {
$count++;
instead of incrementing the counter before checking if $line contains "that", as you have it:
$count++;
if ($line =~ /that/) {
Similarly, I suspect that your push() and join() calls, for stashing a matching line in #array, should also be within the if block, only executed if the line contains "that".
Hope this helps!

Perl wont recognize my if statement

my code:
#!/usr/bin/perl
$line = <STDIN>;
if ($line eq "/n") {
print "That was just a blank line!";
} else {
print "That line of input was: $line";
}
it wont recognize when $line in empty or /n. it will just output "That line of input was:" and then it will be nothing, empty. but it will print text if $line actually is something.
It's "\n" to create a newline.
You should rather try the following so that it matches the blank lines with empty spaces
if ($line =~ /^\s+$/)

perl script miscounting because of empty lines

the below script is basically catching the second column and counting the values. The only minor issue I have is that the file has empty lines at the end (it's how the values are being exported) and because of these empty lines the script is miscounting. Any ideas please? Thanks.
my $sum_column_b = 0;
open my $file, "<", "file_to_count.txt" or die($!);
while( my $line = <$file>) {
$line =~ m/\s+(\d+)/; #regexpr to catch second column values
$sum_column_b += $1;
}
print $sum_column_b, "\n";
I think the main issue has been established, you are using $1 when it is not conditionally tied to the regex match, which causes you to add values when you should not. This is an alternative solution:
$sum_column_b += $1 if $line =~ m/\s+(\d+)/;
Typically, you should never use $1 unless you check that the regex you expect it to come from succeeded. Use either something like this:
if ($line =~ /(\d+)/) {
$sum += $1;
}
Or use direct assignment to a variable:
my ($num) = $line =~ /(\d+)/;
$sum += $num;
Note that you need to use list context by adding parentheses around the variable, or the regex will simply return 1 for success. Also note that, like Borodin says, this will give an undefined value when the match fails, and you must add code to check for that.
This can be handy when capturing several values:
my #nums = $line =~ /(\d+)/g;
The main problem is that if the regex does not match, then $1 will hold the value it received in the previous successful match. So every empty line will cause the previous line to be counted again.
An improvement would be:
my $sum_column_b = 0;
open my $file, "<", "file_to_count.txt" or die($!);
while( my $line = <$file>) {
next if $line =~ /^\s*$/; # skip "empty" lines
# ... maybe skip other known invalid lines
if ($line =~ m/\s+(\d+)/) { #regexpr to catch second column values
$sum_column_b += $1;
} else {
warn "problematic line '$line'\n"; # report invalid lines
}
}
print $sum_column_b, "\n";
The else-block is of course optional but can help noticing invalid data.
Try putting this line just after the while line:
next if ( $line =~ /^$/ );
Basically, loop around to the next line if the current line has no content.
#!/usr/bin/perl
use warnings;
use strict;
my $sum_column_b = 0;
open my $file, "<", "file_to_count.txt" or die($!);
while (my $line = <$file>) {
next if (m/^\s*$/); # next line if this is unsignificant
if ($line =~ m/\s+(\d+)/) {
$sum_column_b += $1;
}
}
print "$sum_column_b\n";

Perl: Searching a file

I am creating a perl script that takes in the a file (example ./prog file)
I need to parse through the file and search for a string. This is what I thought would work, but it does not seem to work. The file is one work per line containing 50 lines
#array = < >;
print "Enter the word you what to match\n";
chomp($match = <STDIN>);
foreach $line (#array){
if($match eq $line){
print "The word is a match";
exit
}
}
You're chomping your user input, but not the lines from the file.
They can't match; one ends with \n the other does not. Getting rid of your chomp should solve the problem. (Or, adding a chomp($line) to your loop).
$match = <STDIN>;
or
foreach $line (#array){
chomp($line);
if($match eq $line){
print "The word is a match";
exit;
}
}
Edit in the hope that the OP notices his mistake from the comments below:
Changing eq to == doesn't "fix" anything; it breaks it. You need to use eq for string comparison. You need to do one of the above to fix your code.
$a = "foo\n";
$b = "bar";
print "yup\n" if ($a == $b);
Output:
yup