我将假设第一个文件(称为A)具有由一个或多个空白字符分隔的三列。第二列可能包含一个算术表达式,其中包含由基本(中缀)运算符分隔的十进制数字和变量。变量值固定在另一个文件中,此后称为B。
准备变量很简单:
my %variables = map {chomp; split /=/, $_, 2} do {
open my $file, "<", $filename_B or die;
<$file>;
};
解析其他文件更加困难。假设它被打开到文件句柄$fileA
中,我们遍历这些行并将每一行分成三个字段:
while (defined(my $line = <$fileA>)) {
chomp $line;
my ($model, $expression, $color) = split /\s+/, $line, 3;
my $value = parseExpression($expression);
print "\t$model $value $color\n"; # use printf to prettyprint if needed
}
然后我们将表达式值与其他数据一起打印出来,假设您要打印到 STDOUT。
我们的 subparseExpression
将在操作符处拆分表达式字符串。变量名将被替换。然后这些操作严格地右关联地执行。虽然这使得解析更容易,但这并不完全自然:3*4+1
评估为15
. 我们使用递归是因为我更喜欢它而不是迭代能够解决多个操作:
sub parseExpression {
my ($string) = @_;
my ($part, $operator, $rest) = ($string =~ /(\w+)([-+*\/^]?)(.*$)/g);
if (not $operator) {
# $part is the whole expression
my $value = exists $variables{$part} ? $variables{$part} : $part;
die if $value =~ /[a-z]/i; # The variable name was not substituted
return $value;
} else {
my $rval = parseExpression($rest);
my $lval = parseExpression($part); # you don't need this
# if there are no variables on the left
my $value = {
'+' => sub {$_[0] + $_[1]},
'-' => sub {$_[0] - $_[1]},
'*' => sub {$_[0] * $_[1]},
'/' => sub {$_[0] / $_[1]},
'^' => sub {$_[0] ** $_[1]},
}->{$operator}->($lval, $rval);
return $value;
}
}
我们使用一个可爱的小调度表来为每个操作员执行适当的计算。您始终可以增强运算符正则表达式和表格以支持其他运算符。
请注意,当前的实现允许数字作为变量名。不是你可能想要的东西,但它让生活更轻松。
随机出现未定义的值可能会出现一些有趣的问题,但是这段代码应该会给你一个指向正确方向的指针。(如果您只允许第二列中的一个操作,则可以删除递归)