On Jul 15, 2006, at 5:15 PM, Daniel D Jones wrote:

Given something like the following:

my @variables = [3, 7, 13, 4, 12];

As an aside, you meant parentheses here, not brackets. (Brackets return a reference to an anonymous array containing the list, not the list itself.)

my @tests = ("2*a+b==c", "c-d+a==e");

I need to be able to evaluate the mathematical truth of the tests, using the
values from @variables, where $variable[0] holds the value of the
variable 'a', $variables[1] holds the value of 'b', etc.  I can do the
evaluation but how do I (reasonably efficiently) substitute the values into the strings? (The length of the array and the exact tests are not known
until run time.)


In C, I'd do this by walking through the test strings character by character,
checking for isalpha, converting the character to its ascii value and
subtracting the ascii value of 'a', and indexing into the array.

This should be easy enough to do, using the length, ord, chr, and substr functions (I haven't tested this):

foreach my $test (@tests) {
   for my $charposition (reverse (0 .. length($test))) {
# go through the string backwards so your count isn't messed up by adding
      # more characters than you took away
      my $char = substr($test, $charposition, 1);
      next if $char !~ /[[:alpha:]]/;
      my $variableindex = ord(lc($char)) - ord("a");
      substr($test, $charposition, 1, $variables[$variableindex]);
   }
}

But it's not a very perl-y way of doing this.

  In Perl I'm
not sure how to do this type of low level character by character processing. The only thing which occurs to me is to split() the string into an array of characters, then walk through that array. Am I on the right track or is
there an easier way to do this in Perl?


If the tests really do look like what you've displayed, then the easiest way would be to make sure your tests are proper perl code, and then run them through "eval". Unlike C, Perl has an entire parser available at runtime for you to use, so there's no need to write your own.

So you'd do something like (also untested):

my ($a, $b, $c, $d, $e) = (3,7,13,4,12);
my @tests = ("2*$a+$b==$c", "$c-$d+$a==$e");

foreach my $test (@tests) {
   if (eval($test)) {
      print "$test is true!\n";
   }
}

This does mean you have to reformat the tests to be valid perl.

An alternative would be (again, untested)

my %value_of = ( a => 3, b => 7, c => 13, d => 4, e => 12);

foreach my $test (@tests) {
   foreach my $variable (keys %value_of) {

      my $value = '$value_of{' . $variable . '}';

      # the above is in single quotes, so will be evaluated during
      # the eval, not during the substitution below

      $test =~ s/$variable/$value/g;
   }
}

foreach my $test (@tests) {
   if (eval($test)) {
      print "$test is true!\n";
   }
}

Either way, using eval is potentially be a security issue since if these are user-supplied tests, then the user can run arbitrary code this way. Fine in some circumstances, bad in others.

--
Aaron Priven, [EMAIL PROTECTED], http://www.priven.com/aaron


--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
<http://learn.perl.org/> <http://learn.perl.org/first-response>


Reply via email to