Why comparison operator == does not work for strings in perl? - perl

I'm new to Perl. I want to understand why does == operator is treating both these strings alike? It works ok if I use eq instead if ==. If name is kuldeep or rahul, it prints 'Right name'.
my $name="kuldeep";
if ($name == "rahul")
{
print 'Right name!',"\n";
}
else
{
print 'Wrong name!','\n';
}

You are mistaken. The numerical equality comparison operator works perfectly fine with strings!
$ perl -e'CORE::say "123" == "123.0" ? "same" : "different"'
same
$ perl -e'CORE::say "123" == "123.1" ? "same" : "different"'
different
In your example, you are asking Perl to compare the numerical value of the string kuldeep (zero with a warning) with the numerical value of the string rahul (zero with a warning), and they are indeed equal.
ALWAYS USE use strict; use warnings;!!!
And use eq to compare strings.

Interpreter realizes (from the == operator) that it's doing a numeric comparison. The value of $name is converted to a numeric, which gets you a 0. "rahul" is converted to a numeric, which is a 0. 0 == 0, so that's true, and thus "Right name" is chosen.
If I compare it against my name, works the same way.
However, if there really is a string with a number in it, like you made either string "12345" (specifically with the quotes), Perl will assume you knew what you were doing by requesting the == operator, and will dutifully auto-convert ("cast" in programmer-speak) that to numeric 12345. Then your comparison will fail.
TL/DR: use 'eq' for string comparison! :-)

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

Comparing empty string with number

I have a global value:
my $gPrevious ='';
# main();
func();
sub func {
my $localval = 52552;
if ($gPrevious != $localval) {
------------
x statements;
}
}
Output:
Argument "" isn't numeric in numeric ne (!=) at line x.
Why do I use the ne operator?
Here I am comparing with an empty string.
The value undef is there specifically so that you can test whether a variable has been defined yet. Initialising a variable to a string when it is to be compared to a number rather defeats this purpose.
You should leave your $gPrevious variable undefined, and test for that inside your subroutine.
Like this
my $gPrevious;
func();
sub func {
my $localval = 52552;
unless (defined $gPrevious and $gPrevious == $localval) {
# x statements;
}
}
Using the '==' or '!=' comparison operator requires having two numbers.
If one of the two is a string that perl can easily make a number such as "1", perl will do what you want and compare the 1.
But: If you compare a string or undef with the '!=' operator, there will be a warning.
In your case, I suggest you simply use
$gPrevious = 0;
# ...
if ( $gPrevious != $local_val ){ #...
which would get rid of the warning and work fine.
Testing for defined is another possibility, while testing for integers is not trivial.
You could use eq instead, but this is problematic, as then for example '1.0' ne '1'.
Perl provides two separate operators for string comparison (eq/ne) and numeric comparison (==/!=). LHS value must match the type of operator being used. In your case, LHS is a string and you are using a numeric operator for comparison. Hence, the error.

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.

Warnings on equality operators

Has something changed in Perl or has it always been this way, that examples like the second ($number eq 'a') don't throw a warning?
#!/usr/bin/env perl
use warnings;
use 5.12.0;
my $string = 'l';
if ($string == 0) {};
my $number = 1;
if ($number eq 'a') {};
# Argument "l" isn't numeric in numeric eq (==) at ./perl.pl line 6.
Perl will be try to convert a scalar to the type required by the context where it is used.
There is a valid conversion from any scalar type to a string, so this is always done silently.
Conversion to a number is also done silently if the string passes a looks_like_number test (accessible through Scalar::Util). Otherwise a warning is raised and a 'best guess' approximation is done anyway.
my $string = '9';
if ( $string == 9 ) { print "YES" };
Converts the string silently to integer 9, the test succeeds and YES is printed.
my $string = '9,8';
if ( $string == 9 ) { print "YES" };
Raises the warning Argument "9,8" isn't numeric in numeric eq (==), converts the string to integer 9, the test succeeds and YES is printed.
To my knowledge it has always been this way, at least since v5.0.
It has been that way.
In the first if, l is considered to be in numeric context. However, l cannot be converted to a number. Therefore, a warning is emitted.
In the second if, the number 1 is considered to be in string context. Therefore the number 1 is converted to the string '1' before comparison and hence no warnings are emitted.
Did you use a lowercase "L" on purpose? It's often hard to tell the difference between a lowercase "L" and one. You would have answered your own question if you had used a one instead.
>perl -wE"say '1' == 0;"
>perl -wE"say 1 eq 'a';"
>
As you can see,
If one needs a number, Perl will convert a string to a number without warning.
If one needs a string, Perl will convert a number to a string without warning.
Very consistent.
You get a warning when you try to convert a lowercase L to a number, but how is that surprising?