文字列の式を解析して計算の結果を返すプログラム。カッコには対応していません。
下の方にダウンロードリンクがあります。
仕組み
1. まず文字列の式を分解します。
例: 10 + 20 * 30 = → [10] [+] [20] [*] [30] [=]
2. 分解した式を逆ポーランド記法の形に並び替えます。
例: [10] [+] [20] [*] [30] [=] → [30] [20] [*] [10] [+] [=]
3. あとは逆ポーランド記法の計算を実行するのみです。
例: [30] [20] [*] [10] [+] [=] → 610
技術
特に難しい方法は使っていませんが、逆ポーランド記法のアルゴリズムを使えば簡単に計算ができます。
カッコや関数には対応していませんが、両方とも簡単に対応させれるはずです。ソースコードも公開しておきますので、ご自由に編集してください。
参考:
ソースコード(選抜)
文字列を解析する
ここではソースコードは割愛させていただきます。
本来は正規表現を使うところなんでしょうけど、将来関数の実装やカッコの実装が面倒になってしまう気がしたので、ここでは1文字ずつ取り出して解析しています。
逆ポーランド記法に変換する部分
string[] operators = OperationPriority[rank]; bool flag = false;// found operation for (int i = this._formula.Count - 1; i >= 0; i--) { foreach (var ope in operators) { // if this rank operation contains the operation if (this._formula[i] == ope) { // if right side is numeric, push to the result list if (i < _formula.Count - 1 && IsNumeric(this._formula[i + 1])) { this._result.Add(this._formula[i + 1]); this._formula.RemoveAt(i + 1); } // if left side is numeric, push to the result list if (i != 0 && IsNumeric(this._formula[i - 1])) { this._result.Add(_formula[i - 1]); this._formula.RemoveAt(i - 1); i--; } this._result.Add(this._formula[i]); this._formula.RemoveAt(i); flag = true; break; } } }
1度でも置き換えしたかどうかを判断するためにflagを使っています。
演算子の検索は後ろから、優先順位の高い演算子から順番に行っています。
this._formulaが元の計算式、this._resultが逆ポーランド記法に変換された計算式です。
検索し、this._resultにプッシュ、元の計算式の演算子とその左右の数値は削除する。というのをひたすら繰り返しているだけですね。
計算する
Stack<double> stack = new Stack<double>(); for (int i = 0; i < this.Count; i++) { // if numeric, if (ConvertRPE.IsNumeric(this[i])) { // push stack stack.Push(double.Parse(this[i])); } else { if (this[i] == "+") stack.Push(stack.Pop() + stack.Pop()); if (this[i] == "-") stack.Push(stack.Pop() - stack.Pop()); if (this[i] == "*") stack.Push(stack.Pop() * stack.Pop()); if (this[i] == "/") stack.Push(stack.Pop() / stack.Pop()); } } if (stack.Count == 0 || stack.Count >= 2) throw new Exception("Invalid Formula"); return stack.Pop();
計算の仕方は[技術]の項目で紹介した記事通りです。演算子があれば、2回ポップし、計算し、プッシュする。それをひたすら繰り返しているだけです。
演算子 ‘=’ だけは特に計算することもないので条件分岐していません。
ダウロード
ソースコード : [wpdm_file id=26] バイナリ : [wpdm_file id=27]