0

I have a list of regexes that I run on a string to convert it from one style of formatting to another. For now, all of these regexes are stored in a file.

Usually, this works fine. If it reads "Frog" into $from, and "Toad" into $to, then "$string =~ s/$from/$to/" changes all frogs into toads, as desired.

Now I want to do something trickier: given a date "2015-04-15", I want to to change it to "04/2015", again reading from a file. If I load "(\d\d\d\d)-(\d\d)-(\d\d)" into $from and "$2/$1" into $to, this doesn't work: it replaces the dates with the literal string "$2/$1", with actual dollar signs in the output. What's do I need to do?

This is a script for home use only. I am happy to use eval{} or any other strange thing if it will make my life simpler.

Mark
  • 132
  • 6

2 Answers2

3

To evaluate the replacement in a substitution, use the /ee modifier. This executes the replacement expression ($to) as Perl code and passes its result (the value of $to) to eval EXPR. As such, $to needs to contain valid Perl code, which means you have to quote the expression to avoid having it evaluated as division.

my $in = '2015-04-15';
my $expected = '04/2015';

my $from = '(\d\d\d\d)-(\d\d)-(\d\d)';
my $to = '"$2/$1"';

$in =~ s/$from/$to/ee;
print $in eq $expected ? 'YES' : 'NO';
ikegami
  • 367,544
  • 15
  • 269
  • 518
choroba
  • 231,213
  • 25
  • 204
  • 289
1

You could use the following:

my $from = '(\d\d\d\d)-(\d\d)-(\d\d)';
my $to = '"$2/$1"';
my $string = '2015-04-15';
$string =~ s/$from/$to/ee;

The above is short for the following:

my $from = '(\d\d\d\d)-(\d\d)-(\d\d)';
my $to = '"$2/$1"';
my $string = '2015-04-15';
$string =~ s/$from/ eval($to) /e;

I prefer the second to the first since it doesn't hide the fact that eval(EXPR) is used. However, both of the above silence errors, so the following would be better:

my $from = '(\d\d\d\d)-(\d\d)-(\d\d)';
my $to = '"$2/$1"';
my $string = '2015-04-15';
$string =~ s/$from/ my $r = eval($to); die $@ if $@; $r /e;

But as you can see, all of the above allow for the execution of arbitrary Perl code. The following would be far safer:

use String::Substitution qw( gsub_modify );

my $from = '(\d\d\d\d)-(\d\d)-(\d\d)';
my $to = '$2/$1';
my $string = '2015-04-15';
gsub_modify($string, $from, $to);
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • And I prefer `\d{n}` :) but well said – vol7ron Apr 15 '15 at 21:45
  • @vol7ron, That's not my code. If you have a style comment for the OP, tell it to him, not me. – ikegami Apr 15 '15 at 22:07
  • Nah, I rather not bloat the answers since you and Choroba have covered the major point. Instead, I would like to point out to you that preference is subjective and what matters is the objective qualities of your preference. E.g. `I prefer the second to the first since ...` to `The benefit of the second over the first is that ...` PCBP is less about preference and more about cost/benefit. – vol7ron Apr 15 '15 at 22:15
  • @vol7ron, I meant you should move the "I prefer `\d{n}`" comment to the Question since it has nothing to do with me or my answer. – ikegami Apr 15 '15 at 22:26
  • @vol7ron, Not everyone sees a benefit in using `s/ /eval(EXPR)/e` over `s/ /EXPR/ee` as a benefit. "Preference" is therefore appropriate. – ikegami Apr 15 '15 at 22:28
  • The mentioning of a preference in an answer is the point that I was making. Preferences are debatable. `eval(EXPR)` isn't the benefit, but you listed the benefit: `it doesn't hide the fact that eval(EXPR) is used`. It's phrasing and semantics is all I was getting at. – vol7ron Apr 15 '15 at 22:30
  • @vol7ron, What's PCBP? – ikegami Apr 15 '15 at 22:30
  • PCBP: Perl Coding Best Practice – vol7ron Apr 15 '15 at 22:31
  • @vol7ron, And I repeat. I've encoutered many that don't see that as a benefit. – ikegami Apr 15 '15 at 22:31
  • It is a benefit, but there are also benefits in not doing so. The fact that it's your preference is less important than the fact as to *why* it's your preference. – vol7ron Apr 15 '15 at 22:32
  • 1
    I fully agree the why is the important part. – ikegami Apr 15 '15 at 22:33