eval-calculation.js
HTML
<h1>eval-calculation.js</h1>
<h2>概要</h2>
<p>eval-calculation.js は引数として与えられた計算式の文字列を評価し、計算結果となる数値を返します。</p>
<h2>設置方法</h2>
<p>外部スクリプトとして<code>eval-calculation.js</code>を指定して下さい。</p>
<pre><code><script src="./eval-calculation.js"></script></code></pre>
<h2>使い方</h2>
<p><code>evalCalculation()</code>の第一引数に計算式となる文字列を指定する事で計算結果となる数値を返します。</p>
<pre><code>evalCalculation('2*3'); // 6</code></pre>
<p>数字と演算子の間に空白を入れても構いません。</p>
<pre><code>evalCalculation('2 * 3 + 5 * 6 / 2'); // 21</code></pre>
<p>負の数を解釈できます。</p>
<pre><code>evalCalculation('-3 * -4'); // 12</code></pre>
<p><code>.1</code> は <code>0.1</code> として評価されます。</p>
<pre><code>evalCalculation('.1 * 5'); // 0.5</code></pre>
<p>JavaScript では IEEE754 の仕様規定によって浮動小数点演算で丸め誤差が生じますが、<code>evalCalculation()</code> は内部的に整数に変換してから演算する為、丸め誤差は生じません。</p>
<pre><code>0.6 * 3; // 1.7999999999999998
evalCalculation('0.6 * 3'); // 1.8</code></pre>
<p><code>eval()</code> と違い、JavaScriptコードを評価出来ませんので、安全に計算式を評価できます。</p>
<pre><code>eval('alert("hoge")'); // alert() が実行される
evalCalculation('alert("hoge")'); // SyntaxError: An expression starts with an unexpected token: a</code></pre>
<h2>仕様/既知の問題</h2>
<ul>
<li>使用可能な演算子は「<code>+-*/</code>」のみです。括弧「<code>()</code>」は使用できません。</li>
<li>文法チェックが甘い為、「<code>2 * 3 @ + 5</code>」のように計算式内に不正な文字が混入されても例外 <code>SyntaxError</code> を返しません(その場合は <code>NaN</code> 値を返す為、返り値で例外処理させる事は可能です)。</li>
</ul>
<h2>更新履歴</h2>
<dl id="history">
<dt>ver.0.9.1 (2016/11/11)</dt>
<dd>
<ul>
<li>初版</li>
</ul>
</dd>
</dl>
<h2>参考リンク</h2>
<ul>
<li><a href="https://gist.github.com/think49/54b074cab2145efddb48765652c74710">eval-calculation.js: 計算式の文字列を評価する - GitHub Gist</a></li>
<li><a href="https://gist.github.com/think49/6aedea62463a741dde0a9ad2c9aa672e">calculator.js: シンプルな電卓 - GitHub Gist</a></li>
</ul>
CSS
pre {
border: solid 1px #999;
padding: 0.6em;
}
#history > dd {
margin: 0;
padding: 0;
}
JavaScript
/**
* eval-calculation.js
* evaluate calculation formula.
*
* @version 0.9.1
* @author think49
* @url https://gist.github.com/think49/54b074cab2145efddb48765652c74710
* @license http://www.opensource.org/licenses/mit-license.php (The MIT License)
*/
var evalCalculation = (function (String, pow, max) {
'use strict';
function getDecimalPartLength (numberString) {
var result = /\.\d+$/.exec(numberString);
return result ? result[0].length - 1 : 0;
}
function calcDyadicOperator (matched, number1, operator, number2) {
var decimalPart = /\.\d+$/, powerNumber1, powerNumber2, result;
switch (operator) {
case '+':
powerNumber1 = pow(10, max(getDecimalPartLength(number1), getDecimalPartLength(number2)));
result = (powerNumber1 * number1 + powerNumber1 * number2) / powerNumber1;
break;
case '-':
powerNumber1 = pow(10, max(getDecimalPartLength(number1), getDecimalPartLength(number2)));
result = (powerNumber1 * number1 - powerNumber1 * number2) / powerNumber1;
break;
case '*':
powerNumber1 = pow(10, getDecimalPartLength(number1));
powerNumber2 = pow(10, getDecimalPartLength(number2));
result = (number1 * powerNumber1) * (number2 * powerNumber2) / (powerNumber1 * powerNumber2);
break;
case '/':
powerNumber1 = pow(10, max(getDecimalPartLength(number1), getDecimalPartLength(number2)));
result = (number1 * powerNumber1) / (number2 * powerNumber1);
break;
default:
console.warn('expression: ' + number1 + operator + number2);
throw new Error(operator + ' is not a operator');
}
// console.log(String(number1) + operator + number2 + '=' + result);
return result;
}
return function evalCalculation (expression) {
var multiplyOrDivide = /(-?(?:\d+(?:\.\d+)?|\.\d+))([*/])(-?(?:\d+(?:\.\d+)?|\.\d+))/g,
...