10

I'm trying to store a s/ / /g regex as a variable (without much luck).

Here is an example that uses a normal match to show what I intend to do.

my %file_structure = (
    header => qr/just another/,
    table  => qr/perl beginner/,
)

Now I can call this using $line =~ $file_structure{'header'} and it will return undef, or true if the pattern matches.

However I would like to say $line =~ $file_structure{'foo'} where $file_structure{'foo'} contains something like s/beginner/hacker/g.

DVK
  • 126,886
  • 32
  • 213
  • 327
Chris R
  • 735
  • 1
  • 9
  • 17

2 Answers2

10

You should store the 2 parts separately:

my %file_structure = (
    foo => {pat => qr/beginner/, repl => 'hacker'},
);

my $line = 'just another perl beginner';
$line =~ s/$file_structure{foo}{pat}/$file_structure{foo}{repl}/;
print "$line\n";

Which would be much safer than resorting to an evil "eval EXPR":

my %file_structure = (
    foo => 's/beginner/hacker/',
);

my $line = 'just another perl beginner';
eval "\$line =~ $file_structure{foo}";
print "$line\n";
tadmc
  • 3,714
  • 16
  • 14
  • The exception is if you need to represent flags like `/e` or `/g` somewhere, because those cannot be represented in the LHS like `/x` or `/i` can. You have to either use the same substitutions flags every time, or use a run-time string `eval` when you cannot. – tchrist Feb 05 '11 at 15:50
  • You have to use this method http://stackoverflow.com/questions/392643/how-to-use-a-variable-in-the-replacement-side-of-the-perl-substitution-operator if you want to include a captured expression in the right hand side. It's safer, anyways, and more general – jjmerelo Dec 26 '13 at 11:15
9

As you have found, there is no way to directly store a substitution regex like you can a match regex (with qr//). You can break the parts up and recombine them as tadmc shows. Another way to do this is to store the substitution in a subroutine:

my %file_structure = (
   foo_uses_default => sub {s/foo/bar/},
   foo_takes_arg    => sub {$_[0] =~ s/foo/bar/},
   foo_does_either  => sub {(@_ ? $_[0] : $_) =~ s/foo/bar/},
);

$file_structure{foo_uses_default}() for ...;
$file_structure{foo_uses_arg}($_)   for ...;
Eric Strom
  • 39,821
  • 2
  • 80
  • 152
  • 2
    You could also do `map $file_structure{foo_whatever}, ...` and I believe any of those three versions would be suitable for an expression to pass in that case. – Chris Lutz Feb 05 '11 at 05:56