Re: math formula substitution and evaluation



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, aaron@xxxxxxxxxx, http://www.priven.com/aaron

.



Relevant Pages

  • parse hash by array element seems to run slow
    ... I've been through the faq's and every web site that focuses on perl ... I iterate the array and search the hash keys to find a match and then ... foreach $verifyArr ...
    (comp.lang.perl.misc)
  • [DGBI] oops, obviously Ive missed something (was: regexp or array?)
    ... foreach { ... Better use an array of precompiled regexpes: ... perl -wle ' ... use Benchmark qw|cmpthese timethese|; ...
    (comp.lang.perl.misc)
  • Re: Is substr only way of getting nth character of string?
    ... I can see it's matching "any one character. ... to chop the string into characters... ... C++ encryption/decryption program in Perl, ... And if I use an array of permuted arrays, ...
    (comp.lang.perl.misc)
  • Re: read and process a file each 3 lines
    ... I am trying to write a second script, in perl, that would print the ... above-mentionned array, and then reckon each value encountered in my ... foreach my $i ...
    (comp.unix.shell)
  • Re: foreach statement output
    ... know about foreach loop workings. ... I've got an incoming array of unknown ... The Perl Cookbook ... My big confusion over this foreach issue is I failed to realize that the ...
    (comp.infosystems.www.authoring.cgi)