0

Context:

Perl script initializes itself based on a user-supplied param-file, then acts on a user-supplied source-file to filter out data and do other operations.

The param-file file contains partial perl expression, which are later suppose to be evaled during runtime, for example:

match:!~  col:1  operand:1|2|3
match:=~  col:1  operand:[^123]
match:=!  col:1  operand:^DATE
match:=~  col:1  operand:^(?:\s|DATE)
match:-~  col:1  operand:^\s
match:eq  col:7  operand:CA
match:eq  col:7  operand:DI
match:ne  col:1  operand:ACCOUNT
match:ne  col:1  operand:POSITIONS
match:==  col:8  operand:999
match:!=  col:8  operand:999

Hmm, and how about something like this? maybe later, but I need that too

match="ne list" '11, 71, 7'

Briefly, my perl will get the match operator from the user and then needs to filter out (or in) records from the source file based on the other params.

One and simple approach, is eval:

next unless eval "$value $match $operand";

Now, given that I know that the $match will always be the same, the use of eval on EACH input of the source-file, sounds like an overkill.

if ($match eq '!~')
{
    next unless $value !~ /$operand/o;
}
elsif ($match eq '=~')
{
    next unless $value =~ /$operand/o;
}
elsif ($match eq 'eq')
{
    next unless $value eq $operand;
}
...

And I was thinking of having a hash lookup, not sure how to do that. (I wonder on that too), also thinking of closures ...

I'm looking for best and most efficient approach?

lzc
  • 919
  • 7
  • 16
  • 1
    Using the `eval` is the least code to maintain. See [Eval::Compile](http://search.cpan.org/dist/Eval-Compile-0.10/lib/Eval/Compile.pm) and [this question](http://stackoverflow.com/questions/24911132/perl-speeding-up-eval) about speeding up the eval. – Kenney Feb 17 '16 at 16:13
  • 2
    I'm not sure there's ever a reason to use `/o`. Using it here makes no sense. – ikegami Feb 17 '16 at 16:17
  • @ikegami I see [your point](http://stackoverflow.com/questions/550258/does-the-o-modifier-for-perl-regular-expressions-still-provide-any-benefit) on `/o` thanks – lzc Feb 17 '16 at 16:42

1 Answers1

2

Using eval EXPR:

$match =~ /^(?:[=!][~=]|eq|ne)\z/
   or die("Unrecognized operator \"$match\"\n");

my $rv;
eval("\$rv = \$value $match \$operand; 1")
   or die $@;

Using a dispatch table:

my %ops = (
   '=~' => sub { $_[0] =~ $_[1] },
   '!~' => sub { $_[0] !~ $_[1] },
   '==' => sub { $_[0] == $_[1] },
   '!=' => sub { $_[0] != $_[1] },
   'eq' => sub { $_[0] eq $_[1] },
   'ne' => sub { $_[0] ne $_[1] },
);

my $op = $ops{$match}
   or die("Unrecognized operator \"$match\"\n");

my $rv = $op->($value, $operand);

I don't see how closures could be of any use.

ikegami
  • 367,544
  • 15
  • 269
  • 518