【问题标题】:How can I parse a mathematical function from user input in Perl?如何从 Perl 中的用户输入解析数学函数?
【发布时间】:2009-11-02 14:35:07
【问题描述】:

我为极坐标函数编写了一个工具。它列出了输入范围中的值,如下所示:

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

基于函数

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

如何从 UserInput(Perl 语法)解析这样的函数并将其分配给变量?

我想避免更改 Perl 脚本;使函数动态而不是静态。

问候并感谢您的阅读。

编辑: 抱歉,四重柱……

感谢您的帮助,但以下 sn-p 给出了错误的值:

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");
}

输入是 abs(1 + tan($t));


(附加信息,从后续合并)

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])); }

【问题讨论】:

  • 到目前为止你有什么?
  • 附注:用chomp代替chop:更安全。
  • 你不应该有 $t = $flRad 而不是 $t = $i 吗?

标签: perl math


【解决方案1】:

您应该查看eval statement。它允许您将字符串评估为 Perl 代码。

例如这段代码:

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

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

给出这个:

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

当您将用户输入作为代码运行时,如果除了 use 之外的其他人正在使用您的脚本,您需要做一些事情来清理用户输入。您可能还想进行替换,例如,用户可以输入 x 而不是 $i 等。如果您想从 eval 捕获错误,请检查 $@ 变量。

【讨论】:

    【解决方案2】:

    根据您的其他工作,我想我会跳过解析的想法,让用户创建一个 Perl 库或子类。他们将代码包装在子例程名称中,并告诉您的脚本库和子名称。您也可以将其与适当的配置文件或命令行选项结合使用。

    【讨论】:

    • 所以没有办法做到这一点?
    • Perl 没有内置任何东西来成为数学解析器。如果这是您问题的症结所在,那么您使用的是错误的语言。有很多方法可以完成这项工作,包括我的建议。
    【解决方案3】:

    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");
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-30
      • 2016-11-08
      • 2013-08-26
      • 1970-01-01
      相关资源
      最近更新 更多