FormulaParser公式解析类
使用新的计算函数,新的算法.速度更快,使用更方便.
算法简介:
format函数:
根据格式化的原则,用一系列的if判断,过滤掉不符合的字符,并分割成数组.再利用括号的一一对应,补全
不匹配的括号.
calculate函数:
根据运算法则,给不同运算符赋予不同权值,再通过权值比较便可以确定运算顺序.
类代码:
/*
* FormulaPareser 公式解析类
* Version 1.0
* 2006.8.11
* Copyright CYJB
*/
//
/*
* 公式解析类,可以计算包含加号(+),减号(-),乘号(*),除号(/),乘方(^),取模(%)以及括号的公式.
* format()格式化公式.格式化遵循以下原则:
* 1."+","-"号前是非数字时,将被认为是正、负号.
* 2.当两个运算符连用(例如"^*"),将使用后面的运算符("+""-"除外).若前面的运算符是"+","-",将被
认为是+1,-1.
* 3.括号前后直接加数字,将被认为是乘以该数字.
* 4.当"("与")"不匹配时,将认为是缺少最外层括号.
* 5.自动去除公式的非法字符(除了".0123456789+-/*%^()").
* 6.自动去除"(数字)"中的括号
* calculate()计算公式.可以传入字符串(会自动调用format函数格式化字符串),也可以直接传入数组
* (不会调用format函数).直接传入数组需要注意格式,但是计算会更快速.
* 注意:请注意输入数据的大小,否则可能会计算错误(超过flash计算能力).
*/
//
class FormulaParser {
public static function format(s:String):Array {
//格式化公式
var data:Array = [];
var backets:Array = [];
//括号个数记录
var n = 0;
var s1 = s.charAt(n);
while (s1.length == 1) {
var k = s1.charCodeAt(0);
var l = data.length-1;
var s2 = data[l];
var k2 = (s2.charCodeAt(s2.length-1) == undefined) ? 0 :
s2.charCodeAt(s2.length-1);
if (k>=48 && k<=57) {
//trace("这个是数字");
if (k2 == 46 || (k2>=48 && k2<=57)) {
//trace("前面是数字或.");
data[l] += s1;
} else if (s2 == "--") {
//trace("前面是负号");
data[l] = "-"+s1;
} else if (s2 == ")") {
//trace("前面是)");
data.push("*");
data.push(s1);
} else {
//trace("前面是开头或+-*/%^或(");
data.push(s1);
}
} else if (k == 46) {
//trace("这个是.");
if (k2>=48 && k2<=57) {
//trace("前面是数字");
if (s2.indexOf(".") == -1) {
//只能有一个小数点
data[l] += s1;
}
} else if (s2 == "--") {
//trace("前面是负号");
data[l] = "-0.";
} else if (s2 == ")") {
//trace("前面是)");
data.push("*");
data.push("0.");
} else if (k2 != 46) {
//trace("前面是开头或+-*/%^或(");
data.push("0.");
}
} else if (k == 43 || k == 45) {
//trace("这个是+-");
if (k2 == 41 || (k2>=48 && k2<=57)) {
//trace("前面是数字或)");
data.push(s1);
} else if (k2 == 46) {
//trace("前面是.");
data[l] = data[l].slice(0, -1);
data.push(s1);
} else if (k == 45) {
//trace("这个是-");
if (s2 == "--") {
//trace("前面是负号");
data.pop();
} else if (k2 == 45) {
//trace("前面是-");
data[l] = "+";
} else if (k2 == 43) {
//trace("前面是+");
data[l] = "-";
} else {
//trace("前面是开头或+-*/%^或(");
data.push("--");
}
}
} else if (k == 37 || k == 42 || k == 47 || k == 94) {
//trace("这个是*/%^");
if (k2 == 41 || (k2>=48 && k2<=57)) {
//trace("前面是数字或)");
data.push(s1);
} else if (k2 == 46) {
//trace("前面是.");
data[l] = data[l].slice(0, -1);
data.push(s1);
} else if (s2 == "--") {
//trace("前面是负号");
data[l] = "-1";
data.push(s1);
} else if (k2 == 45 || k2 == 43) {
//trace("前面是+-");
data.push("1");
data.push(s1);
} else if (s2 != undefined && k2 != 40) {
//trace("前面是*/%^");
data[l] = s1;
}
} else if (s1 == "(") {
//trace("这个是(");
backets.push("(");
if (k2 == 41 || (k2>=48 && k2<=57)) {
//trace("前面是数字或)");
data.push("*");
data.push("(");
} else if (k2 == 46) {
//trace("前面是.");
data[l] = data[l].slice(0, -1);
data.push("*");
data.push("(");
} else if (s2 == "--") {
//trace("前面是负号");
data[l] = "-1";
data.push("*");
data.push("(");
} else {
//trace("前面是开头或+-*/%^或(");
data.push("(");
}
} else if (s1 == ")") {
//trace("这个是)");
if (s2 != undefined) {
if (backets[backets.length-1] == "(") {
backets.pop();
} else {
backets.push(")");
}
}
if (k2 == 41 || (k2>=48 && k2<=57)) {
//trace("前面是数字或)");
data.push(")");
} else if (s2 == "--") {
//trace("前面是负号");
data[l] = "-1";
data.push(")");
} else if (k2 == 46) {
//trace("前面是.");
data[l] = data[l].slice(0, -1);
data.push(")");
} else if (k2 == 40) {
//trace("前面是(");
data.pop();
} else if (s2 != undefined) {
//trace("前面是+-*/%^");
data[l] = ")";
}
}
n++;
s1 = s.charAt(n);
}
//防止最后一位不合理
while (data[data.length-1] == "(") {
data.pop();
backets.pop();
}
var m = data[data.length-1];
if (m == "+" || m == "-" || m == "*" || m == "/" || m == "%" || m == "^") {
data.pop();
} else if (m == "--") {
data.pop();
data.pop();
} else if (m.substr(-1) == ".") {
data[data.length-1] = m.slice(0, -1);
}
//防止括号不匹配
var bs = backets.join("");
var n1 = bs.split("(").length;
var n2 = bs.split(")").length;
if (n1 != 0) {
n1--;
}
if (n2 != 0) {
n2--;
}
while (n1--) {
data.push(")");
}
while (n2--) {
data.splice(0, 0, "(");
}
//去除"(数字)"中的括号
var i = 1;
//第一、二位不可能是")"
while (i++<data.length) {
if (data == ")") {
if (data[i-2] == "(") {
data.splice(i, 1);
data.splice(i-2, 1);
i -= 2;
}
}
}
return data;
}
public static function calculate(s):Number {
//计算公式
var data:Array = [];
//参数的类型检察
if (s instanceof Array) {
data = s;
} else if (typeof (s) == "string") {
data = format(s);
}
var m:Array = [];
//括号数据存储
var num:String = "0";
var l = data.length;
var sign:String = "+";
var n:Number = 0;
var i = 0;
while (i<l) {
if (data == "(") {
m.push([num, sign, n, false]);
if (data[i+1] == "(") {
i++;
num = "0";
sign = "+";
n = 0;
} else {
num = data[i+1];
sign = data[i+2];
, n = getPriority(sign);
i += 3;
}
} else {
var sign2 = data[i+1];
if (sign2 == ")") {
num = evals(num, sign, data);
while (m[m.length-1][3]) {
var arr = m.pop();
num = evals(arr[0], arr[1], num);
}
m[m.length-1][3] = true;
while (data[i+2] == ")") {
while (m[m.length-1][3]) {
var arr = m.pop();
num = evals(arr[0], arr[1], num);
}
m[m.length-1][3] = true;
i++;
}
sign = data[i+2];
n = getPriority(sign);
while (m[m.length-1][2]>=n && m[m.length-1][3]) {
var arr = m.pop();
num = evals(arr[0], arr[1], num);
}
i += 3;
if (i>=l) {
for (var j in m) {
num = evals(m[j][0], m[j][1], num);
}
}
} else {
var n2 = getPriority(sign2);
if (n>=n2) {
num = evals(num, sign, data);
while (m[m.length-1][2]>=n2 && m[m.length-
1][3]) {
var arr = m.pop();
num = evals(arr[0], arr[1], num);
}
} else {
m.push([num, sign, n, true]);
num = data;
}
sign = sign2;
n = n2;
i += 2;
}
}
}
return Number(num);
}
private static function getPriority(s:String):Number {
//计算权值
if (s == "+" || s == "-") {
return 1;
} else if (s == "*" || s == "/" || s == "%") {
return 2;
} else if (s == "^") {
return 3;
} else {
return 0;
}
}
private static function evals(n1:String, s:String, n2:String):String {
//计算数据
switch (s) {
case "+" :
return String(Number(n1)+Number(n2));
case "-" :
return String(Number(n1)-Number(n2));
case "*" :
return String(Number(n1)*Number(n2));
case "/" :
return String(Number(n1)/Number(n2));
case "%" :
return String(Number(n1)%Number(n2));
case "^" :
return String(Math.pow(Number(n1), Number(n2)));
}
}
}
分享到:
相关推荐
使用运算树进行解释,大大提高了公式的解析效率 支持 + - * / ^ %三角函数: 比较运算: FormulaParser fp = new FormulaParser(); fp.AddParameter ("a","100"); fp.AddParameter("b", "20"); fp.AddParameter("c", ...
公式解析器 库提供了一个Parser类,用于评估excel和数学公式。安装建议的安装公式分析器的方法是使用以下命令通过 : $ npm install hot-formula-parser --save Node.js: var FormulaParser = require ( 'hot-...
- **FormulaParser**:负责解析用户定义的公式,将其转换为系统可识别的格式,并保存到公式库中。 - **Calculator**:执行计算任务,包含各种运算符,可以根据需求扩展。 - **Formula**:表示单个公式,封装了...
公式解析器 Formula Parser是用于解析和评估以字符串形式给出的数学公式的库。 支持: 运算符:+,-,*,/,^ 变量:x,y,z,a,b 小数点为“。”的数字E表示法中的数字常数:pi,e,Inf 功能:sqrt,abs,sin,cos...
在实际编程中,我们可以创建一个解析器类 `FormulaParser`,该类包含一个正则表达式来匹配公式中的变量占位符(如 `#{dddd}`)。`parse` 方法接收公式字符串、中间公式映射(`formulas`)和基础数据映射(`values`)...