tags:

views:

111

answers:

4

What is the cleanest way of picking up a match variable from a substitution in Perl I sometimes find myself writing

    s/(something)// ;
    my $x = $1 ;

then I realise that if the s/ / / fails $1 might be carrying over a value from a previous match. So I try

    my  $x = 'defaultvalue' ;
    if ( s/(something)// )
    {
     $x = $1 ;
    }

Is this the cleanest way of doing it?

+4  A: 

TMTOWTDI.

The idiomatic Perl usually seen might be somthing like:

my $x='defaultvalue';

$x=$1 if (s/(something)//) ;
drewk
mobrule
And the very idiomatic `$x=$defaultvalue unless (s/(something)/$x=$1/e)` which is only recommended for sadists ;-)
drewk
+1  A: 

@mobrule points out in comments that you can use

s{(...)}{} && ($x=$1)

I would recommend

s{(...)}{} and $x = $1;

I used s{}{} because I hate it when Markdown marks // as comments in Perl code.

and has lower precedence than && which makes it possible to remove the parentheses around the assignment.

From perldoc perlop:

As more readable alternatives to && and || when used for control flow, Perl provides the and and or operators (see below). The short-circuit behavior is identical. The precedence of "and" and "or" is much lower, however, so that you can safely use them after a list operator without the need for parentheses:

Sinan Ünür
+2  A: 

As others have pointed out, TIMTOWTDI.

I'd personnally wrap it up as a single expression, so as not to distract too much from the point:

my $x = s/(something)// ? $1 : 'defaultvalue';
JB
A: 

This is highly subjective, and the best answer will depend greatly on how well it matches your coding style, but I'll throw my hat into the ring anyway.

My favorite for assignments with defaults is the tertiary operator:

my $x = ($data =~ s/(foo)//) ? $1 : 'defaultvalue';

Although the new (well, not that new, 5.10 introduced it) "defined or" operator can reduce the need for the tertiary statement in many cases. I generally use it as such:

my $var = defined($candidate) ? $candidate : 'default';

But now that can be simplified to:

my $var = $candidate // 'default';

or

my $var = 'default';
$var //= $candidate;
kbenson
Just be careful with `//` operator and trying to be too obtuse, you might get: `$x=(s/...//, $1) // $defaultvalue` which is a more readable form of `$x=(s/...//, $1) || ($defaultvalue)` While this works in many cases, it is not testing the match -- it is testing a defined $1. Fine in a solo block, death if there was a successful previous match with an unsuccessful match in this test. That is why I like the more direct `$x=$1 if (s/...//).` Works in every case and every block.
drewk