Conditional Statement giving seemingly wrong answer: What am I missing - perl

So I have to make a simple calculator in Perl that maintains an accumulator and does simple operations. The accumulator starts at 0 and then changes based on the results that I receive. At the moment I am only trying to get addition to work. When I check to ensure that the operator entered is + something goes wrong. For instance:
Accumulator: 0
Operator: Anything put here results in addition. Including this sentence.
Operand: 4
Accumulator: 4
It catches numbers but nothing else. I have tried using grep and a list of the operators. I have exhausted all of my ideas. Here is my code (Fyi first post so help me with any noob errors):
my $running = 1;
my $accum = "0";
my $operator;
my $operand;
print("Welcome to the simple, command line calculator.\n");
print("To terminate, press Control-C.\n\n");
while ($running){
print("\nAccumulator: ".$accum."\n");
print("Operator: ");
$operator = <STDIN>;
if ($operator == "+"){
print("Operand: ");
operand = <STDIN>;
$accum += $operand;
}
else{
print("Invalid operator: ".$operator."\n");
}
}

Perl doesn't remove the ending newline from input unless you use the -l option, so you're comparing "+" against "+\n". Usually you want to do soemthing like chomp($operator);.
That said, your real problem is that == does numeric comparison, and both "+" and "+\n" evaluate to 0 in numeric context. (Using -w, as you should always do, would warn you about this.) Use the eq operator for string comparison.

== compares numbers, not strings. If you compare strings, the strings will be converted to numbers; for non-numeric strings, this means they become 0. So $operator == "+" becomes 0 == 0.
For strings, use eq instead. Additionally, keep in mind that <STDIN> will preserve newlines; make sure to chomp $operator as well.

Related

Matching inside square Brackets in Perl

When I try to match 2 variables which are same, it works until there is a square bracket in perl for me.
For ex, VAR1 = u6701, VAR2 = u6701 matches and gives me EQUAL
However, VAR1 = aw[101], VAR2 = aw[101] gives me UNEQUAL.
I use $VAR1 == $VAR2 to check and both the variables are strings. Please help.
Thanks.
== is the numeric equality operator in Perl, it checks that two things are equal as numbers. eq is the string equality operator, that's what you want to be using. "1" and "01.00" are equal as numbers but not as strings. Here's the docs on all the equality operators. There is also the pretty good online book Beginning Perl.
Why == sometimes works is because Perl is pretty liberal, to the point of desperation, about interpreting strings as numbers. Often it will simply consider a string to be 0, but sometimes it will find a number in the string and use it. For example, "101aw" will be interpreted as 101, but "aw101" is 0. Do not rely on this.
BTW Perl will warn you about all this, but not by default. You have to turn on strict and warnings and I highly recommend you do and deal with all the issues it brings up. It will save you (and us) lots of time.
In perl in order to check two string values I recommend you to use eq
for eg
if($VAR1 eq $VAR2)
return true;
else
return false;
== tests equality for numbers.
eq does the same for strings.
You can also use the cmp operator, which is the non-numerical equivalent of the <=> operator:
$result = $string1 cmp $string2;
$result will be:
`0` if the strings are equal
`1` if string1 is greater than string2
`-1` if string1 is less than string2

How to check if arguments are correct using Perl?

I am new to Perl and I try to check if my 2 arguments starts with "-" or "--". My code:
if ($ARGV[0] ~= /^-*/ || $ARGV[1] ~= /^-*/) {
But when the arguments are "abc abc" it still passes the condition.
Thanks in advance.
First of all, the binding operator is =~, not ~=. It's easy to remember, as it has a counterpart - !~ (mean 'doesn't match'). But that's a simple typo.
What's more important, however, is the approach itself: if you want to match for '-' and '--', the pattern should be written as /^--?/. It's not clear, however, whether or not you consider '---abc' a valid argument. If not, the regex should look like the following:
/^--?[^-]+$/
... otherwise it's enough just to check the first character of the corresponding param against '-', and using regex is clearly an overkill. For example:
if (substr($ARGV[0], 0, 1) eq '-' || substr($ARGV[1], 0, 1) eq '-') {
# invalid params detected
}
Still, the way you tried to implement it, it should have been written as /^-+/, not /^-*/. The last one matches for any number of hyphens at the start of the string - including 0 hyphens. That's why abc string passed the check. In fact, any string would have passed the check.

Perl: If always returning true

I am just getting back into Perl programming so I appologize if this is an easy/stupid question.
My If statement is returning true (never going to the else) and I'm not really sure why. For example this code never prints "getshere":
#showName = ("Matt","Matt","Matt","Gym","Gym");
$counter=0;
foreach (#showName)
{
if ($showName[$counter]==$showName[$counter+1])
{
print "$showName[$counter] equ $showName[$counter+1]\n";
}
else
{
print "getshere";
}
$counter++;
}
Can you please tell me what I am doing wrong?
Thank you!
== is numeric comparison, and strings like 'Matt' and 'Gym' all have the numeric value 0, so they're all == to each other. For string comparison, use eq instead:
if ($showName[$counter] eq $showName[$counter+1])
(I recommend enabling warnings, by the way, by adding use warnings; near the start of your script. Had you done that, you would have received a helpful message warning you that you were applying a numeric equality-test to non-numeric values.)
The == operator converts strings to numbers and does numeric comparison. To compare strings, use eq. To test if strings are greater or less than eachother, use cmp.
if ($showName[$counter] eq $showName[$counter+1])

Perl thinks all strings are equal

Edit: I did try using eq instead of == earlier, and it did not work. For some reason now it does. It's possible that there was another error at that point which prevented it from working, but now this has been resolved. Thank you.
I'm trying to do some simple validation. I want to make sure the redirect url being fed through a variable begins with a particular site or not. If it does, the redirect goes through, if not, it redirects to the root of the site. Seems pretty straight forward, right?
$redir = $input{'redirect'};
$redir_sub = substr($redir, 0, 21);
if ($redir_sub == "http://www.mysite.com") {
print "Location: $redir \n\n";
}else{
print "Location: http://www.mysite.com \n\n";
}
The thing is, no matter what variable I place in there, it the "if" returns as true. I could put my favorite webcomic in there and it'll redirect to it, despite the string not matching. For example this:
$redir = $input{'redirect'};
$redir_sub = "http://www.yahoo.com"
if ($redir_sub == "http://www.mysite.com") {
print "Location: $redir_sub \n\n";
}else{
print "Location: http://www.mysite.com \n\n";
}
That redirects to yahoo! What is going on?
if ($redir_sub == "http://www.mysite.com")
should be
if ($redir_sub eq "http://www.mysite.com")
as eq is string equality operator, and using == forces number comparison so in this case condition always evaluates to trues as 0 == 0 is true.
Operator == is used to compare numbers. You should replace it with operator eq
TL;DR: use eq not ==!
Perl as a language seems to have a problem: It uses the same data type (the scalar) for a lot of different things, including strings and numbers. A scalar is both at the same time, not just one of those. Perl has no type annotations, and there is no way to indicate if a variable holds a string or a number.
This produces problems when we consider equality tests. Assuming two scalars $a = "42.0" and $b = 42. Are they equal? Yes and no:
The strings "42" and "42.0" are not the same thing! These are not equal.
The numbers 42 and 42.0 are equal!
As indicated above, Perl does not use a type system to solve this ambiguity. Rather, it uses different sets of operators for string and numeric operations:
eq ne lt le gt ge cmp
== != < <= > >= <=>
Your problem is that you are not using
use warnings;
Which is why Perl is allowing you to make this mistake. You are using the numeric equality operator to compare strings. Hence, Perl first tries to convert each parameter to a number. And since your strings do not begin with numbers (and do not look like numbers), they are converted to zero 0. Hence your expression
if ($redir_sub == "http://www.mysite.com")
Really means this
if (0 == 0)
Which of course always returns true.
If you had been using warnings, you would have gotten the errors:
Argument "http..." isn't numeric in numeric eq (==) at ...
Argument "http..." isn't numeric in numeric eq (==) at ...
Which would have been a hint as to your problem that you should be using eq and not == to compare strings.
== does numeric comparison. eq does string comparison. When you use a string as a number, perl passes your string through your c library's aton(). So you're really asking your computer if 0 == 0 which is true.

What does this code do?

This does what I would like it to
if (grep {/$dn/} #ad_sys) {
$is_system = 1;
}
but this always returns 1.
if (grep $_ == $dn, #ad_sys) {
$is_system = 1;
}
What does the second piece do?
== is used for numeric comparison, if you need string comparison use eq.
It filters those elements from the list #ad_sys that are numerically equal to $dn.
Then, if the result is not empty, the condition is true and the if-block is entered.
There are two differences between the two pieces of code.
Firstly, as others have pointed out already, there is the issue of the numeric comparison operator.
But secondly, /$dn/ checks to see if $_ contains the data in $dn. $_ eq $dn checks if $_ is exactly equal to $dn.
This difference could cause a problem, for example, if your data consisted of lines read from a file that hadn't been chomped to remove the newline.