最初のファイル( Aと呼ばれる)には、1つ以上の空白文字で区切られた3つの列があると想定します。2番目の列には、基本(中置)演算子で区切られた10進数と変数を含む算術式が含まれる場合があります。変数値は別のファイルに固定されており、以降Bと呼ばれます。
変数の準備は簡単です。
my %variables = map {chomp; split /=/, $_, 2} do {
open my $file, "<", $filename_B or die;
<$file>;
};
他のファイルの解析はより困難です。ファイルハンドルで開かれていると仮定して$fileA
、行をループし、各行を3つのフィールドに分割します。
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;
}
}
かわいい小さなディスパッチテーブルを使用して、各オペレーターに適切な計算を実行します。追加の演算子をサポートするために、いつでも演算子の正規表現とテーブルを拡張できます。
現在の実装では、変数名として数値が許可されていることに注意してください。あなたが望むかもしれないものではありませんが、それは人生を楽にします。
未定義の値がランダムに発生するという興味深い問題があるかもしれませんが、このコードは正しい方向へのポインターを提供するはずです。(2番目の列で1つの操作のみを許可する場合は、再帰を削除できます)