Perl simple comparison == vs eq - perl

On the accepted answer for
String compare in Perl with "eq" vs "=="
it says that First, eq is for comparing strings; == is for comparing numbers.
"== does a numeric comparison: it converts both arguments to a number and then compares them."
"eq does a string comparison: the two arguments must match lexically (case-sensitive)"
You can ONLY use eq for comparing strings but
both eq AND == works for comparing numbers
numbers are subset of strings so i just dont understand why you would ever use ==
Is there a reason why you would want to use == for comparing numeric values over just using eq for all?

Here is an example of why you might want ==:
$a = "3.0";
print "eq" if $a eq "3"; # this will not print
print "==" if $a == 3; # this will print
3.0 is numerically equal to 3, so if you want them to be equal, use ==. If you want to do string comparisons, then "3.0" is not equal to "3", so in this case you would use eq. Finally, == is a cheaper operation than eq.

String comparisons are just plain different, especially with numbers.
#s_num=sort {$a <=> $b} (20,100,3); # uses explicit numeric comparison
print "#s_num\n"; # prints 3 20 100, like we expect
#s_char=sort (20,100,3); # uses implicit string comparison
print "#s_char\n"; # prints 100 20 3, not so good.
-Tom Williams

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

Change meaning of the operator "+" in perl

Currently "+" in perl means addition, in my project, we do string concatenation a lot. I know we can concatention with "." operator, like:
$x = $a . $b; #will concatenate string $a, and string $b
But "+" feels better. Wonder if there is a magic to make the following do concatenation.
$x = $a + $b;
Even better, make the it check the operator type, if both variables ($a, $b) are numbers, then do "addition" in the usual sense, otherwise, do concatenation.
I know in C++, one can overload the operator. Hope there is something similar in perl.
Thanks.
Yes, Perl too offers operator overloading.
package UnintuitiveString;
use Scalar::Util qw/looks_like_number/;
use overload '+' => \&concat,
'.' => \&concat,
'""' => \&as_string;
# Additionally, the following operators *have* to be overridden
# I suggest you raise an exception if an implementation does not make sense
# - * / % ** << >> x
# <=> cmp
# & | ^ ~
# atan2 cos sin exp log sqrt int
# 0+ bool
# ~~
sub new {
my ($class, $val) = #_;
return bless \$val => $class;
}
sub concat {
my ($self, $other, $swap) = #_;
# check for append mode
if (not defined $swap) {
$$self .= "$other";
return $self;
}
($self, $other) = ($other, $self) if $swap;
return UnintuitiveString->new("$self" . "$other");
}
sub as_string {
my ($self) = #_;
return $$self;
}
sub as_number {
my ($self) = #_;
return 0+$$self if looks_like_number $$self;
return undef;
}
Now we can do weird stuff like:
my $foo = UnintuitiveString->new(4);
my $bar = UnintuitiveString->new(2);
print $foo + $bar, "\n"; # "42"
my ($num_x, $num_y) = map { $_->as_number } $foo, $bar;
print $num_x + $num_y, "\n"; # "6"
$foo += 6;
print $foo + "\n"; # "46"
But just because we can do such things does not at all mean that we should:
Perl already has a concatenation operator: .. It's perfectly fine to use that.
Operator overloading comes at a massive performance cost. What previously was a single opcode in perl's VM is now a series of method calls and intermediate copies.
Changing the meaning of your operators is extremely confusing for people who actually know Perl. I stumbled a few times with the test cases above, when I was surprised that $foo + 6 wouldn't produce 10.
Perl's scalars are not a number or a string, they are both at the same time and are interpreted as one or the other depending on their usage context. This is actually half-true, and the scalars have different representations. They could be a string (PV), an integer (IV), a float (NV). However, once a PV is used in a numerical context like addition, a numerical value is determined and saved alongside the string, and we get an PVIV or PVNV. The reverse is also true: when a number is used in a stringy context, the formatted string is saved alongside the number. The looks_like_number function mentioned above determines whether a given string could represent a valid number like "42" or "NaN". Because just using a scalar in some context can change the representation, checking that a given scalar is a PV does not guarantee that it was intended to be a string, and an IV does not guarantee that it was intended to be an integer.
Perl has two sets of operators for a very good reason: If the “type” of a scalar is fluid, we need another way to explicitly request certain behavior. E.g. Perl has numeric comparison operators < <= == != >= > <=> and stringy comparison operators lt le eq ne ge gt cmp which can behave very differently: 4 XXX 12 will be -1 for <=> (because 4 is numerically smaller than 12), but 1 for cmp (because 4 comes later than 1 in most collation orders).
Other languages suffer a lot from having operators coerce their operands to required types but not offering two sets of operators. E.g. in Java, + is overloaded to concat strings. However, this leads to a loss of commutativity and associativity. Given three values x, y, z which can be either strings or numbers, we get different results for:
x + y and y + x – string concatenation is not commutative, whereas numeric addition is.
(x + y) + z and x + (y + z) – the + is not associative as soon as one string enters the playing field. Consider x = 1, y = 2, z = "4". Then the first evaluation order leads to "34", whereas the second leads to "124".
In Java, this is not a problem, because the language is statically typed, and because there are very few coercions (autoboxing, autounboxing, widening conversions, and stringification in concatenation). However, JavaScript (which is dynamically typed and will perform conversions from strings to numbers for other operators) shows the exact same behavior. Oops.
Stop this madness. Now. Perl's set of operators (barring smartmatch) is one of the best designed parts of the language (and its type system one of the worst parts from a modern viewpoint). If you dislike Perl because its operators make sense, you are free to use PHP instead (which, by the way, also uses . for concatenation to avoid such issues) :P

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?

How do I compare two strings in Perl?

How do I compare two strings in Perl?
I am learning Perl, I had this basic question looked it up here on StackOverflow and found no good answer so I thought I would ask.
See perldoc perlop. Use lt, gt, eq, ne, and cmp as appropriate for string comparisons:
Binary eq returns true if the left argument is stringwise equal to the right argument.
Binary ne returns true if the left argument is stringwise not equal to the right argument.
Binary cmp returns -1, 0, or 1 depending on whether the left argument is stringwise less than, equal to, or greater than the right argument.
Binary ~~ does a smartmatch between its arguments. ...
lt, le, ge, gt and cmp use the collation (sort) order specified by the current locale if a legacy use locale (but not use locale ':not_characters') is in effect. See perllocale. Do not mix these with Unicode, only with legacy binary encodings. The standard Unicode::Collate and Unicode::Collate::Locale modules offer much more powerful solutions to collation issues.
cmp Compare
'a' cmp 'b' # -1
'b' cmp 'a' # 1
'a' cmp 'a' # 0
eq Equal to
'a' eq 'b' # 0
'b' eq 'a' # 0
'a' eq 'a' # 1
ne Not-Equal to
'a' ne 'b' # 1
'b' ne 'a' # 1
'a' ne 'a' # 0
lt Less than
'a' lt 'b' # 1
'b' lt 'a' # 0
'a' lt 'a' # 0
le Less than or equal to
'a' le 'b' # 1
'b' le 'a' # 0
'a' le 'a' # 1
gt Greater than
'a' gt 'b' # 0
'b' gt 'a' # 1
'a' gt 'a' # 0
ge Greater than or equal to
'a' ge 'b' # 0
'b' ge 'a' # 1
'a' ge 'a' # 1
See perldoc perlop for more information.
( I'm simplifying this a little bit as all but cmp return a value that is both an empty string, and a numerically zero value instead of 0, and a value that is both the string '1' and the numeric value 1. These are the same values you will always get from boolean operators in Perl. You should really only be using the return values for boolean or numeric operations, in which case the difference doesn't really matter. )
In addtion to Sinan Ünür comprehensive listing of string comparison operators, Perl 5.10 adds the smart match operator.
The smart match operator compares two items based on their type. See the chart below for the 5.10 behavior (I believe this behavior is changing slightly in 5.10.1):
perldoc perlsyn "Smart matching in detail":
The behaviour of a smart match depends on what type of thing its arguments are. It is always commutative, i.e. $a ~~ $b behaves the same as $b ~~ $a . The behaviour is determined by the following table: the first row that applies, in either order, determines the match behaviour.
$a $b Type of Match Implied Matching Code
====== ===== ===================== =============
(overloading trumps everything)
Code[+] Code[+] referential equality $a == $b
Any Code[+] scalar sub truth $b−>($a)
Hash Hash hash keys identical [sort keys %$a]~~[sort keys %$b]
Hash Array hash slice existence grep {exists $a−>{$_}} #$b
Hash Regex hash key grep grep /$b/, keys %$a
Hash Any hash entry existence exists $a−>{$b}
Array Array arrays are identical[*]
Array Regex array grep grep /$b/, #$a
Array Num array contains number grep $_ == $b, #$a
Array Any array contains string grep $_ eq $b, #$a
Any undef undefined !defined $a
Any Regex pattern match $a =~ /$b/
Code() Code() results are equal $a−>() eq $b−>()
Any Code() simple closure truth $b−>() # ignoring $a
Num numish[!] numeric equality $a == $b
Any Str string equality $a eq $b
Any Num numeric equality $a == $b
Any Any string equality $a eq $b
+ − this must be a code reference whose prototype (if present) is not ""
(subs with a "" prototype are dealt with by the 'Code()' entry lower down)
* − that is, each element matches the element of same index in the other
array. If a circular reference is found, we fall back to referential
equality.
! − either a real number, or a string that looks like a number
The "matching code" doesn't represent the real matching code, of course: it's just there to explain the intended meaning. Unlike grep, the smart match operator will short-circuit whenever it can.
Custom matching via overloading
You can change the way that an object is matched by overloading the ~~ operator. This trumps the usual smart match semantics. See overload.
The obvious subtext of this question is:
why can't you just use == to check if two strings are the same?
Perl doesn't have distinct data types for text vs. numbers. They are both represented by the type "scalar". Put another way, strings are numbers if you use them as such.
if ( 4 == "4" ) { print "true"; } else { print "false"; }
true
if ( "4" == "4.0" ) { print "true"; } else { print "false"; }
true
print "3"+4
7
Since text and numbers aren't differentiated by the language, we can't simply overload the == operator to do the right thing for both cases. Therefore, Perl provides eq to compare values as text:
if ( "4" eq "4.0" ) { print "true"; } else { print "false"; }
false
if ( "4.0" eq "4.0" ) { print "true"; } else { print "false"; }
true
In short:
Perl doesn't have a data-type exclusively for text strings
use == or !=, to compare two operands as numbers
use eq or ne, to compare two operands as text
There are many other functions and operators that can be used to compare scalar values, but knowing the distinction between these two forms is an important first step.
print "Matched!\n" if ($str1 eq $str2)
Perl has seperate string comparison and numeric comparison operators to help with the loose typing in the language. You should read perlop for all the different operators.
And if you'd like to extract the differences between the two strings, you can use String::Diff.
I came looking for a solution where in perl I could compare if A > B or Z < AA. Nothing here worked reliably for me so I came up with my own solution. The tricks is to assign a number for each letter
For example
A=1
B=2
C=3 and so on
Then when time comes to compare if A > B you get the corresponding numbers and compare them in this case 1 > 2
Heres working perl code.
# header
use warnings;
use strict;
#create a hash of letters
my %my_hash_lookup;
my $letter_counter=0;
foreach my $letters ('A'..'ZZ')
{
#print "$letters \n";
$letter_counter++;
my $key = $letters;
my $keyValue = $letter_counter;
$my_hash_lookup{$key}=$keyValue;
}
my $size = keys %my_hash_lookup;
print "hash size: $size ...\n";
#get number value of string letters
my $my_hash_value1 = $my_hash_lookup{"A"};
my $my_hash_value2 = $my_hash_lookup{"B"};
if ( (defined $my_hash_value1) && (defined $my_hash_value2))
{
if ($my_hash_value1 == $my_hash_value2)
{
#equal
}
elsif ($my_hash_value1 > $my_hash_value2)
{
#greater than
}
elsif ($my_hash_value1 < $my_hash_value2)
{
#less than
}
}