Kadiam
Kadiam

Reputation: 401

In Perl, what is the meaning of if (s/^\+//)?

In a Perl/Tk code I found a conditional statement as below

if (s/^\+//)
{
   #do something
}
elsif (/^-/)
{
   #do another thing
}

Seems like some pattern matching has been done. But I cannot understand it. Can anyone help me understanding this pattern matching?

Upvotes: 2

Views: 4233

Answers (4)

Joel Berger
Joel Berger

Reputation: 20280

The other answers have given a summary of how the code works, but not much of why. Here is a simple example of why one might use such logic.

#!/usr/bin/env perl

use strict;
use warnings;

my $args = {};

for ( @ARGV ) {
  if ( s/^no// ) {
    $args->{$_} = 0;
  } else {
    $args->{$_} = 1;
  }
}

use Data::Dumper;
print Dumper $args;

When you call the script like

./test.pl hi nobye

you get

$VAR1 = {
          'hi' => 1,
          'bye' => 0
        };

The key is the string, however if it is preceded by no then remove it (to get the key in question) and instead set the value to 0.

The OP's example is a little more involved, but follows the same logic.

  • if the key starts with a +, remove it and do something
  • if the key starts with a -, don't remove it and do something else

Upvotes: 2

simbabque
simbabque

Reputation: 54373

They are both regular expressions. You can read up on them at perlre and perlretut. You can play around with them on http://www.rubular.com.

They both implicitly do something with $_. There probably is a while or foreach around your lines of code without a loop variable. In that case, $_ becomes that loop variable. It might for instance contain the current line of a file that is being read.

  1. If the current value of $_ contains a + (plus) sign as the first character at the beginning of the string, #do somehting.
  2. Else if it contains a - (minus) sign, #do another thing.

In case 1. it also replaces that + sign with nothing (i.e. removes it). It does not remove the - in 2. however.


Let's look at an explanation with YAPE::Regex::Explain.

use YAPE::Regex::Explain;
print YAPE::Regex::Explain->new(qr/^\+/)->explain();

Here it is. Not really helpful in our case, but a nice tool nonetheless. Note that the (?-imsx and ) parts are the default things Perl implies. They are always there unless you change them.

The regular expression:

(?-imsx:^\+)

matches as follows:

NODE                     EXPLANATION
----------------------------------------------------------------------
(?-imsx:                 group, but do not capture (case-sensitive)
                         (with ^ and $ matching normally) (with . not
                         matching \n) (matching whitespace and #
                         normally):
----------------------------------------------------------------------
  ^                        the beginning of the string
----------------------------------------------------------------------
  \+                       '+'
----------------------------------------------------------------------
)                        end of grouping
----------------------------------------------------------------------

Update: As Mikko L in the comments pointed out, you should maybe refactor/change this piece of code. While it probably does what it is supposed to, I believe it would be a good idea to make it more readable. Whoever wrote it obviously didn't care about you as the later maintainer. I suggest you do. You could change it to:

# look at the content of $_ (current line?)
if ( s/^\+// )
{
  # the line starts with a + sign,
  # which we remove!

  #do something
}
elsif ( m/^-/ )
{
  # the line starts witha - sign
  # we do NOT remove the - sign!

   #do another thing
}

Upvotes: 12

Eugene Yarmash
Eugene Yarmash

Reputation: 150021

This code is equivalent to

if ($_ =~ s/^\+//) {  # s/// modifies $_ by default
   #do something
}
elsif ($_ =~ m/^-/) {  # m// searches $_ by default
   #do another thing
}

s/// and m// are regexp quote-like operators. You can read about them in perlop.

Upvotes: 3

Thilo
Thilo

Reputation: 262734

Those are regular expressions, used for pattern matching and substitution.

You should read up on the concept, but as for your question:

s/^\+//

If the string started with a plus, remove that plus (the "s" means "substitute"), and return true.

/^-/

True if the string starts with a minus.

Upvotes: 5

Related Questions