Re: math formula substitution and evaluation
- From: aaron@xxxxxxxxxx (Aaron Priven)
- Date: Sat, 15 Jul 2006 18:17:50 -0700
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
.
- References:
- math formula substitution and evaluation
- From: Daniel D Jones
- math formula substitution and evaluation
- Prev by Date: Re: math formula substitution and evaluation
- Next by Date: Re: math formula substitution and evaluation
- Previous by thread: Re: math formula substitution and evaluation
- Next by thread: Re: math formula substitution and evaluation
- Index(es):
Relevant Pages
|