简体   繁体   English

如何从Perl中的用户输入解析数学函数?

[英]How can I parse a mathematical function from user input in Perl?

I wrote a tool for polar functions. 我写了一个用于极函数的工具。 It lists values from an input range like that: 它列出了如下输入范围内的值:

0 Grad: (0 RAD|1 RES)  
20 Grad: (0.349065850398866 RAD|1.3639702342662 RES)  
40 Grad: (0.698131700797732 RAD|1.83909963117728 RES)  
60 Grad: (1.0471975511966 RAD|2.73205080756888 RES)  
80 Grad: (1.39626340159546 RAD|6.67128181961771 RES)  
100 Grad: (1.74532925199433 RAD|4.67128181961771 RES)  
120 Grad: (2.0943951023932 RAD|0.732050807568878 RES)  
140 Grad: (2.44346095279206 RAD|0.16090036882272 RES)  
160 Grad: (2.79252680319093 RAD|0.636029765733797 RES)  
180 Grad: (3.14159265358979 RAD|1 RES)

It is based of the function 它基于功能

 abs(1 + tan($_[0]));

How can I parse such a function from UserInput (Perl syntax) and assign it to a variable? 如何从UserInput(Perl语法)解析此类函数并将其分配给变量?

I want to avoid changing the Perl script; 我想避免更改Perl脚本; making the function dynamic instead of static. 使函数动态而不是静态。

Greets and thanks for reading. 问候并感谢您的阅读。

EDIT: sorry for quadrupelpost.... 编辑:对quadrupelpost抱歉。

Thanks for the help, but the following snippet gives wrong values: 感谢您的帮助,但以下代码段给出了错误的值:

print("Eingabe: Funktion (phi = $t); PERL syntax!: > ");
$iFunktion = <STDIN>;
chop($iFunktion);

print("Eingabe: Grad Start: > ");
$iGradStart = <STDIN>; 
chop($iGradStart);

print("Eingabe: Grad End: > ");
$iGradEnd = <STDIN>; 
chop($iGradEnd);

print("Eingabe: Schrittweite: > ");
$iSchrittweite = <STDIN>; 
chop($iSchrittweite);

print("\nBerechne Funktion von $iGradStart bis $iGradEnd Grad mit einer Schrittweite von $iSchrittweite\n");


for ($i = $iGradStart; $i < $iGradEnd; $i = $i + $iSchrittweite)
{
    $flRad = &deg2rad($i);
    #$flResult = &Compute($flRad);
    $t = $i;
    $flResult = eval($iFunktion);
    print("$i Grad: ($flRad RAD|$flResult RES)  \n");
}

Input was abs(1 + tan($t)); 输入为abs(1 + tan($ t));


(additional info, merged from follow-up) (其他信息,来自后续行动)

print("Eingabe: Grad Start: > "); 
$iGradStart = <STDIN>; 
chop($iGradStart); 

print("Eingabe: Grad End: > "); 
$iGradEnd = <STDIN>; 
chop($iGradEnd); 

print("Eingabe: Schrittweite: > "); 
$iSchrittweite = <STDIN>; chop($iSchrittweite); 
print("\nfrom $iGradStart to $iGradEnd Grad with $iSchrittweite\n"); 
for ($i = $iGradStart; $i <= $iGradEnd; $i = $i + $iSchrittweite) 
{ 
  $flRad = &deg2rad($i); 
  $flResult = &Compute($flRad); 
  print("$i Grad: ($flRad RAD|$flResult RES) \n"); 
} 

sub Compute { return abs(1 + tan($_[0])); }

You should look at the eval statement . 您应该查看eval语句 It allows you to evaluate a string as Perl code. 它允许您将字符串评估为Perl代码。

For example, this code: 例如,此代码:

print "Function? ";
chomp($function = <STDIN>);

for ($i = 0;$i < 10;$i++) {
  print $i,"->",eval($function),"\n";
}

Gives this: 给出以下内容:

Function? $i * $i
0->0
1->1
2->4
3->9
4->16
5->25
6->36
7->49
8->64
9->81

As you're running user input as code, if someone other than use is using your script, you'll want to do something to sanitise user input. 在将用户输入作为代码运行时,如果使用以外的其他人正在使用脚本,则需要执行一些操作来清理用户输入。 You may also want to do a substitution so users could, for example, enter x instead of $i etc. If you want to catch errors from eval check the $@ variable. 您可能还想进行替换,以便用户可以输入x而不是$i等。如果要捕获eval错误,请检查$@变量。

Depending on what else you have going on, I think I'd skip the parsing idea and have the users create a Perl library or subclass. 根据您正在进行的其他事情,我想我会跳过解析思路,而是让用户创建Perl库或子类。 They wrap their code in subroutine names and tell your script the library and the sub name. 他们将代码包装在子例程名称中,并告诉您的脚本库和子名称。 You might also combine that with a proper config file or command-line options. 您也可以将其与适当的配置文件或命令行选项结合使用。

Math::Expression::Evaluator almost does what you want, except that has no abs() and no way to add user functions (callbacks.) It took me about five minutes to add some rudimentary support, thought. Math :: Expression :: Evaluator 几乎可以完成您想要的一切,除了没有abs()并且没有添加用户功能(回调)的方法。我花了大约五分钟的时间来添加一些基本支持。

#!/usr/bin/perl
use strict;
use warnings;
use Math::Trig;
use Math::Expression::Evaluator;

my $expr = join ' ', @ARGV;
die "No expression provided" unless $expr;
my $m = Math::Expression::Evaluator->new;
# NOT in the distribution
$m->add_user_function('abs', sub { abs($_[0]) });
my $func = $m->parse($expr);
die "Cannot parse" unless $func;
for my $i (0 .. 10){
    my $rads = deg2rad($i);
    my $res = $func->val({x => $_});
    print("$i Grad: ($rads RAD|$res RES)  \n");
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM