/** * String形式の数式を計算するクラス * * code is originally from * http://ericlin2.tripod.com/math2/EvaluateEqMxt.html * * 改造点 * ・ユーザー定義変数を使用可能にした。 * ・ユーザー定義関数も使用可能にした。 * * var num1 : Number = Calculator.evaluate("pow(2,4)"); * var num2 : Number = Calculator.evaluate("(x+y)*2", {x:5, y:3}); * var num3 : Number = Calculator.evaluate("f()*2", {f:function():void{return 5}}); */ package { public class Calculator { public static const operatorSet : String = "+-*/^+-"; protected static var _argObj : Object /** * @param str 数式。Math関数はsqrt(a,b)といった形で使用可能。 * @param argObj ユーザー定義変数。ここで{x:1}等と定義することで、数式内で変数が使える */ public static function evaluate(str : String, argObj:Object=null) : Number { //ユーザー定義変数を一時保存 argObj = (argObj)? argObj : {}; str = str.split(" ").join(""); //trim off the space if any if (!str.length>0) { return 0; } // search for +,-,*,/,* , skip string in parenthesis and cut into two pieces accordingly // after this step , only function, parenthesis, variable or number are left var str2 : String = maskParenthesis(str); for (var k :int = 0; k=0) { if ((k<=1) && operatorSet.indexOf(str2.charAt(i-1))>=0) { //something like 3*-4; start = i-1; //################continue continue; } var lStr : String = str.substr(0, i); var rStr : String = str.substr(i+1, str.length-i-1); return handleOperator(op, lStr, rStr, argObj); } } // now we get only the parenthesis, function and pure number/variable here; now check function start = str.indexOf("("); if (start>=0) { var functionName : String = (str.substr(0, start)).toLowerCase(); var contentInParenthesis : String = str.substr(start+1, str.length-start-2); return handleFunction(functionName, contentInParenthesis, argObj); } // After those steps , only variable and pure number are left here, now check variable if (isNaN(Number(str))) { //ここでユーザー定義変数も使えるように改造 if( Math[str]!=undefined ){ return Math[str]; }else if(argObj[str]!=undefined && argObj[str] is Number){ return argObj[str]; } } // variable are screened off, here is pure value return Number(str); }; protected static function handleOperator(operator:String, lStr:String, rStr:String, argObj:Object):Number { var num1 : Number = evaluate(lStr, argObj); var num2 : Number = evaluate(rStr, argObj); var val : Number switch (operator) { case "+" : val = num1+num2; break case "-" : val = num1-num2; break case "*" : val = num1*num2; break case "/" : val = num1/num2; break case "^" : val = Math.pow(num1, num2); break default : val = 0; } return val } /** * random 等引数0の呼び出しがあまりうまくいかなかったので色々改造 */ protected static function handleFunction(functionName : String, contentInParenthesis:String, argObj:Object) : Number { if (!functionName.length>0) { // pure parenthesis return evaluate(contentInParenthesis, argObj); } // It is a function, now check how many parameters var str2 :String = maskParenthesis(contentInParenthesis); var str : String = contentInParenthesis; var params : Array = []; if( str!="" && str2 !=""){ var i : * = -1; while (i=str2.indexOf(",")>=0) { var lStr : String = str.substr(0, i); str2 = str2.substr(i+1, str2.length-i-1); str = str.substr(i+1, str.length-i-1); params.push(evaluate(lStr, argObj)); } params.push(evaluate(str, argObj)); } var val:Number if(Math[functionName]!=undefined) { val = Math[functionName].apply(null, params); }else if(argObj[functionName]!=undefined){ val = argObj[functionName].apply(null, params); } return val; } // ()内部をマスクする。 /** * 5+4*(4-3)+2 が 5+4*(((((+2 になる? * */ protected static function maskParenthesis( str : String ) : String { var parenthesisStack : Number = 0; var temp : String = ""; for( var i : int = 0; i < str.length; i++ ) { var char :String = str.substr(i, 1); if( char == "(" ){ parenthesisStack++; } if( char == ")" ){ parenthesisStack--; } temp += (parenthesisStack == 0 ? char : "("); } if( parenthesisStack != 0 ){ // "(" と ")" の数が合わない throw new Error("The number of ( and ) does not match"); return ""; } return temp; } } }