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>