How to reset $1 perl variable?

Viewed 313

I try to do regex matching:

$address =~ s/$re_region//;
$new_address_h->{ region     } =  $1  //'';

# $1 =  undef; # ERROR: Modification of a read-only value attempted at ...
$address =~ s/$re_city//;
$new_address_h->{ city       } =  $1;

When city is not matched I want it is filled with undef. But when city is not matched $1 has value from previous match. Why? I expect that when matching fails then its output has no values, even special variables. like eval flushes $@

Is it possible without additional ifs?

2 Answers

It's documented behaviour (perlvar):

Perl sets these variables when it has a successful match, so you should check the match result before using them.

You can use do with a ternary operator to populate the hash:

$new_address_h->{region} = do { $address =~ s/$re_region// ? $1 : undef };
$new_address_h->{city}   = do { $address =~ s/$re_city//   ? $1 : undef };

Alternatively, populate the the hash with undefs and then replace them with values if there's a match:

my $new_address_h = { region => undef, city => undef };
$address =~ s/$re_region// and $new_address_h->{region} = $1;
$address =~ s/$re_city//   and $new_address_h->{city}   = $1;

The common way is to just match, not replace, and populate in list assignment:

($new_address_h->{region}) = $address =~ /$re_region/;
($new_address_h->{city})   = $address =~ /$re_city/;

Finally I use ternary operator without do:

$new_address_h->{ region } =  $address =~ s/$re_region//?
    $1 : '';

$new_address_h->{ city   } =  $address =~ s/$re_city//?
    $1 : undef;
Related