http://www.perlmonks.org?node_id=1028580

abualiga has asked for the wisdom of the Perl Monks concerning the following question:

Hi there, I'm trying to understand interpolation of operators within strings. Specifically, can mathematical operators be interpolated within strings and evaluated as operators. Below is some example code to make my question clear. Many thanks!

my @ops = ( '-', '+', '*', '/' ); for( @ops ) { my $a = "2 $_ 2"; say $a; }

Is it possible iterate over these operations and perform calculations?

Replies are listed 'Best First'.
Re: interpolating operators within strings
by NetWallah (Canon) on Apr 14, 2013 at 01:34 UTC
    Try using "eval" : see "perldoc -f eval".

    my $a = eval "2 $_ 2";
    This is not considered "safe" because it is possible to inject unwanted code into the eval string.
    It is fine for testing purposes.

                 "I'm fairly sure if they took porn off the Internet, there'd only be one website left, and it'd be called 'Bring Back the Porn!'"
            -- Dr. Cox, Scrubs

Re: interpolating operators within strings
by kcott (Archbishop) on Apr 14, 2013 at 02:16 UTC

    G'day abualiga,

    As ++NetWallah points out, eval can be unsafe.

    If your eval code started off like this:

    $ perl -Mstrict -Mwarnings -E 'say eval for map { "12 $_ 3" } qw{+ - * + / % **}' 15 9 36 4 0 1728

    Using a despatch table like this is a safer option.

    $ perl -Mstrict -Mwarnings -E ' my %op_hash = ( q{+} => sub { $_[0] + $_[1] }, q{-} => sub { $_[0] - $_[1] }, q{*} => sub { $_[0] * $_[1] }, q{/} => sub { $_[0] / $_[1] }, q{%} => sub { $_[0] % $_[1] }, q{**} => sub { $_[0] ** $_[1] }, ); say for map { $op_hash{$_}->(12, 3) } qw{+ - * / % **}; ' 15 9 36 4 0 1728

    And you can add your own sanity checks:

    $ perl -Mstrict -Mwarnings -E ' my %op_hash = ( q{+} => sub { $_[0] + $_[1] }, q{-} => sub { $_[0] - $_[1] }, q{*} => sub { $_[0] * $_[1] }, q{/} => sub { die "Divide by zero!" if $_[1] == 0; $_[0] / +$_[1] }, q{%} => sub { $_[0] % $_[1] }, q{**} => sub { $_[0] ** $_[1] }, ); say for map { $op_hash{$_}->(12, 0) } qw{+ - * / % **}; ' Divide by zero! at -e line 6.

    I don't know what context you're intending to use this in: the overload pragma may be of some use.

    Update: s/unsafe:/unsafe./ and added "If your eval code started off like this: "

    -- Ken

      How is anything in your example unsafe? I am reminded of MJD's righteous takedown of a similar superstitious warning (see slide 31).
        Thanks educated_foo, I'd not seen that presentation before, and it's well worth a read :)

      Your insight is much appreciated! I was trying to do addition and subtraction of two lists of paired numbers and wanted to avoid separate loops.

        Well, in that case, you might be better off with the pairwise function of List::MoreUtils:

        $ perl -Mstrict -Mwarnings -E ' use List::MoreUtils qw{pairwise}; my @x = 0 .. 3; my @y = map { 10 + $_ } @x; say for pairwise { "$a + $b = " . ($a + $b) . "; $b - $a = " . ($b - $a) } @x, @y; ' 0 + 10 = 10; 10 - 0 = 10 1 + 11 = 12; 11 - 1 = 10 2 + 12 = 14; 12 - 2 = 10 3 + 13 = 16; 13 - 3 = 10

        Note how $a holds @x elements and $b holds @y elements. These ($a & $b) are the same special variables used by sort, so don't declare them; they're described in perlvar - SPECIAL VARIABLES - General Variables. You can use them in either order: cf. $a + $b and $b - $a.

        -- Ken

      If you first use a regex to remove anything that isn't an operator, a number format, or a space, then it's perfectly safe to eval from there.