205

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.

Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
PJT
  • 3,439
  • 5
  • 29
  • 40
  • 3
    You should first consult the excellent documentation that comes with Perl. – Sinan Ünür Jul 24 '09 at 01:37
  • 5
    You might want to check out a book such as _Learning Perl_ (which I co-authored). There weren't good answers to this question because it's very basic. A tutorial will help you pick up the basics quickly. – brian d foy Jul 24 '09 at 16:58

7 Answers7

213

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.

Community
  • 1
  • 1
Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
  • 9
    Just one more, ne for not equal. – PJT Jul 24 '09 at 01:56
  • 5
    You might want to mention that $str1 =~ "$str2" (not /$str2/) will check if $str2 is a substring of $str1. – Daniel C. Sobral Jul 24 '09 at 02:35
  • @Daniel use `index` to see if a string is a substring of another one. – Sinan Ünür Jul 24 '09 at 02:47
  • 3
    @Daniel: there's not much practical difference between =~"$str2" and =~/$str2/ (or just =~$str2 for that matter); index is the right tool, but if you need to use a regex for some reason, do =~/\Q$str2\E/. – ysth Jul 24 '09 at 06:11
  • Can't understand why `!=` is not the same as `ne` - or at least (and for sure) it doesn't always work the same way. Most of the time only `ne` works reliable enough? Any idea why? – Ilia Ross Jan 22 '15 at 19:47
  • 1
    @IliaRostovtsev `!=` and `ne` are not the same, because `!=` and `ne` are defined to be different. How hard is that?! Being a numeric comparison operator, `!=` converts both its operands to numbers `perl -E 'say "equal" if not "a" != "b"'`. – Sinan Ünür Jan 24 '15 at 17:36
  • @SinanÜnür Thank you very much for your explanation. It seems a bit different than it's in `JavaScript` or `PHP`. Cheers. – Ilia Ross Jan 24 '15 at 19:36
  • I think it would worth briefly describing what [smartmatch](http://perldoc.perl.org/perlop.html#Smartmatch-Operator) is as in the other cases, it is also good to know that it is experimental and its behavior might change. _"The `~~` operator compares its operands "polymorphically", determining how to compare them according to their actual types (numeric, string, array, hash, etc.)"_ – zsltg Jan 11 '16 at 20:16
  • @SinanÜnür: I'm not suggesting you should recommend it. However I think a brief description about it would be beneficial. – zsltg Jan 12 '16 at 18:48
  • @Zsolt Maybe [you can figure it out and post your own answer](http://www.nntp.perl.org/group/perl.perl5.porters/2015/09/msg230881.html). There is absolutely no need to bring smartmatch into this question, or, IMNSHO, use it in any program. – Sinan Ünür Jan 13 '16 at 04:48
  • I am not sure, how is perl 'sort' exactly supposed to work, but it seems, it worked only with cmp not with lt or gt operators. – FantomX1 Jun 18 '21 at 16:44
149
  • 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. )

Brad Gilbert
  • 33,846
  • 11
  • 78
  • 129
  • 9
    I like this answer more. Short simple examples are usually more helpful for newbies, than only banal multipage docs reference. – Zon Oct 23 '13 at 08:24
  • @Zon except that return values for `eq`, `gt`, `lt` etc are not correct ... They return true or false. Only `cmp` returns specific numeric values. – Sinan Ünür Apr 01 '15 at 16:58
  • Perl 6 uses the same operators except it uses `leg` instead of `cmp` which is used for generic comparisons instead. – Brad Gilbert Jul 25 '15 at 02:40
17

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.

Brad Gilbert
  • 33,846
  • 11
  • 78
  • 129
Chas. Owens
  • 64,182
  • 22
  • 135
  • 226
  • It's not changing slightly: it's changing radically. Smart matching for anything un-simple is seriously broken. – brian d foy Jul 24 '09 at 16:56
  • 1
    The link should probly change since the docs have changed in the mean time. [5.14.2](http://perldoc.perl.org/5.14.2/perlsyn.html#Smart-matching-in-detail) [current](http://perldoc.perl.org/perlop.html#Smartmatch-Operator) – Brad Gilbert Mar 01 '13 at 16:44
11

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.

Community
  • 1
  • 1
Brent Bradburn
  • 51,587
  • 17
  • 154
  • 173
10
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.

Matthew Scharley
  • 127,823
  • 52
  • 194
  • 222
1

And if you'd like to extract the differences between the two strings, you can use String::Diff.

Brad Gilbert
  • 33,846
  • 11
  • 78
  • 129
Helen Craigman
  • 1,443
  • 3
  • 16
  • 25
  • If you are going to link to Perl documentation, it is usually recommended to use Permalinks which will always link to the newest version of the module. http://search.cpan.org/perldoc/String::Diff http://search.cpan.org/perldoc?String::Diff http://p3rl.org/String::Diff http://metacpan.org/module/String::Diff http://metacpan.org/pod/String::Diff **Done** – Brad Gilbert Feb 14 '14 at 16:16
0

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
            }
            
        }
Sam B
  • 27,273
  • 15
  • 84
  • 121