Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

How to evaluate a mathematical formula that is stored in another file?

by skooma (Novice)
on Mar 20, 2018 at 11:09 UTC ( #1211295=perlquestion: print w/replies, xml ) Need Help??

skooma has asked for the wisdom of the Perl Monks concerning the following question:

I have 2 files. One file contains the variables and values it's in the form of excel sheet. The second file contains the mathematical equation in .txt format. My code has to evaluate the formula in a .txt file line by line using the values from the values extracted for the excel sheet. Note: Each line can contain a different formula.

use strict; use diagnostics; use warnings; use Spreadsheet::ParseXLSX; my %data; #initializing hash my $logfile = $ARGV[0]; #Take the file from command line my $parser = Spreadsheet::ParseXLSX->new(); #Initialize Parser my $workbook = $parser->parse($logfile); #Assign the .xlsx file to b +e parsed if ( !defined $workbook ) { die $parser->error(), ".\n"; #Kill parser if .xlsx file not pr +esent } for my $worksheet ( $workbook->worksheets() ) { #Loop till end of +worksheet my ( $row_min, $row_max ) = $worksheet->row_range(); #Getting + max and min row my ( $col_min, $col_max ) = $worksheet->col_range(); #Getting + max and min col for my $row ( $row_min .. $row_max ) { #Loop till max row in +a sheet for my $col ( $col_min .. $col_max ) { #Loop till max col + in a sheet #Adding Hash Elements from Excel my $name_add = $worksheet->get_cell( $row, $col+2 ); next unless $name_add; my $cell_add = $worksheet->get_cell( $row, $col+3 ); next unless $cell_add; my $name = $field_name_add->value(); my $val = $cell_add->value(); $data{$name} = $val ; } } } #=======================================Reading_Formula_File======== +=============================== my $formulae = $ARGV[1]; open ( RD, $formulae ) or die "Couldnt open file $formulae, $!"; while ( $_ = <RD>){ eval $_; printf("%s",$z); }

The expression does not evaluate at all. I am a newbie in Perl.

  • Comment on How to evaluate a mathematical formula that is stored in another file?
  • Download Code

Replies are listed 'Best First'.
Re: How to evaluate a mathematical formula that is stored in another file?
by hippo (Bishop) on Mar 20, 2018 at 11:21 UTC

    Here's an SSCCE:

    #!/usr/bin/env perl use strict; use warnings; use Test::More tests => 1; my $x = 7; my $y = 5; my $z; my $formula = '$z = $x + $y'; eval $formula; is ($z, 12)

    Note that your script would be essentially executing arbitrary perl code from another source so this is a big security risk and you ought not to do it.

      Thanks. What if I wanted to execute a basic mathematical formula? That is, not a Perl code from another source file but just a mathematical expression, #start of formula file z = a + b #end of formula file a and b values will be taken from my data/parameter file. This is what I am going for. Sorry if my explanation is not clear.

        If the expressions aren't Perl then you cannot eval them. Sounds like you want Math::Symbolic instead.

Re: How to evaluate a mathematical formula that is stored in another file?
by hdb (Monsignor) on Mar 20, 2018 at 11:22 UTC

    From the first part of your code it looks like you are storing your variables and values in the %data hash in the form $data{"variable name"} = "value". In order to work, your formulae have to use those variables and values in the very same format.

    I would think it be useful to see a couple of examples.

    Update: Here is some basic code to get you started:

    use strict; use warnings; my %data = ( x => 5, y => 7, z => 2 ); my @formulae = ( 'x + y', 'z + 3', 'x ** z', 'a + x', 'x /= y', 'x - x' ); for my $formula (@formulae) { print "Processing formula $formula\n\t"; my @error = (); while ($formula =~ s|([a-z]+)|$data{$1}//' '|e) { push @error, $1 unless exists $data{$1}; } if (@error) { print "Error: unknown variable(s) @error\n\n"; } else { my $result = eval($formula); if( defined $result) { print "Result: $formula = $result\n\n"; } else { print "Syntax error in $formula\n\n"; } } }

      Thanks your code greatly helped me to get part of my results. But can you explain these two lines below? Thanks.

      while ($formula =~ s|([a-z]+)|$data{$1}//' '|e) { push @error, $1 unless exists $data{$1};

        In my simplistic example code I assumed that a variable name consists of lower case letters. The regular expression ([a-z]+) finds any consecutive sequence of (at least one) lower case letters. It is then replaced by $data{$1}//' ' where $1 stands for the found sequence. $data{$1} is the value assigned to that sequence ie the variable name. If it does not exist in the hash %data the expression //' ' ensures that a blank is used instead (also makes sure that no warning is issued).

        I have used s||| instead of the more common s/// to avoid confusion on the // operator.

        In the push statement I store the found sequence as in $1 in the array @error if %data did not contain a value for the variable. This is some kind of crude error handling and I can list the names of variables without values further below in the code.

        Again, this is only a simplistic example, and not the only way to look at your requirements. The evil eval is still not fully defused and one could create havoc with mischievous inputs in the values or formulae provided.

Re: How to evaluate a mathematical formula that is stored in another file?
by choroba (Archbishop) on Mar 20, 2018 at 12:05 UTC
    See the Enhanced Marpa Calculator on how to evaluate maths expressions with variables without the dangers of eval.

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
Re: How to evaluate a mathematical formula that is stored in another file?
by thanos1983 (Parson) on Mar 20, 2018 at 11:26 UTC

    Hello skooma,

    Welcome to the Monastery. From my point of view your code is copy paste from the package or a tutorial regarding the Spreadsheet::ParseXLSX. From your description you not doing anything that you describe.

    So from my point of view in order as to help you is not about to solve it for you but guide you step by step to understand what happens. If I understand correctly you want to read the data from the excel sheet into a hash and then evaluate them with the *.txt file. If so did you try to print your hash to see what data you have inside? Hint Data::Dumper.

    Let's assume that the data inside the hash is what you need to store, then you read line by line the text file, how do you compare the hash data with the lines?

    Try to approach these minor problems before proceeding and I think you will solve it.

    If you are still not able to resolve it, provide us sample of your input of both of the files and the expected output. We can not guess the data for you.

    Hope this helps, BR.

    Seeking for Perl wisdom...on the process of learning...not there...yet!
Re: How to evaluate a mathematical formula that is stored in another file?
by tybalt89 (Prior) on Mar 21, 2018 at 02:16 UTC

    You sure didn't say much about what your formulas look like, but here's a little parser for what you did show (and a few extras, like * and parens).

    #!/usr/bin/perl # http://perlmonks.org/?node_id=1211295 use strict; use warnings; use Data::Dump 'pp'; while(<DATA>) { print "\nformula $_"; my %data = qw( a 2 b 3 ); # for testing, set from your other file pp 'before', \%data; calc($_, \%data); pp 'after ', \%data; } sub error { die s/\G/ *** Expected @_ -->/r, "\n" } sub want { /\G\s+/gc; /\G\Q$_[1]\E/gc ? shift : error "'$_[1]'" } sub calc { local $_ = shift; our $dataref = shift; expr(0); pos($_) == length $_ or error 'End of Source'; } sub expr { our $dataref; /\G\s+/gc; my $value = /\G(\w+)\s*=/gc ? do { my $t = $1; $dataref->{$t} = expr(0) } : /\G(\w+)/gc ? $dataref->{$&} // 0 : /\G\(/gc ? want expr(0), ')' : error 'Operand'; $value = /\G\s+/gc ? $value : $_[0] <= 1 && /\G\+/gc ? $value + expr(2) : $_[0] <= 2 && /\G\*/gc ? $value * expr(3) : return $value while 1; } __DATA__ z = a + b z = a * b z = a * b + a * b z = a + b * a + b

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1211295]
Approved by marto
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (5)
As of 2022-07-04 02:40 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?