一个简单的表达式计算,有时候我们要在程序中对某些自定义的公式进行计算。
如定制化的一些条件,如根据某个变量来决定界面元素的颜色
我们只要对这个类稍微扩展即可,例如我们重载getObjValue方法,
然后定义一个变量池,就可以实现对诸如 calculateExp("50-Qty*((1+2)*3)+2")的计算。
getObjValue()中实现对于Qty可以从变量池获得数据。
更多的扩展可以参照后面的类,可以做一个自己的脚本语言解释器。
Polynomial dt =new Polynomial();
long begin =System.currentTimeMillis();
VariableFactory vf = new VariableFactory();
vf.setVariable("A","Select * from mis_rwe where a=");
vf.setVariable("B","150");
vf.setVariable("conf ","'5'");
dt.setDataFactory(vf);
dt.calcuPolyn("set A=IIF(obj(b)=150:add(obj(a)+obj(conf),str(\" order by desc\")),:空)");//strExp
dt.calcuPolyn("set A=str('新的变量值:')+obj(a)");//strExp
System.out.println(vf.getVariable("a"));
dt.calcuPolyn("set B=100");//strExp
dt.calcuPolyn("set A=IIF(obj(b)=100:str('(变更B变量后)')+obj(a),:空)");//strExp
System.out.println(vf.getVariable("a"));
dt.calcuPolyn("set A=replace(Obj(A),变更B变量后,str('替换函数操作后'))");//strExp
System.out.println(vf.getVariable("a"));
dt.calcuPolyn("set A=replace(\"测试 test\" + ' W J G ', test, newstr)");//strExp
System.out.println(vf.getVariable("a"));
for(int i=0; i<10;i++)
dt.calcuPolyn("set B=obj(b)+'100'");
System.out.println("B="+vf.getVariable("b"));
System.out.println("运行时间:"+(System.currentTimeMillis()-begin) +"毫秒");
/*--------------------------------------------------
1.实现表达式的计算;
2.实现简单的加、减、乘、除、括号运算。
3.例:calculateExp("50-10*((1+2)*3)+2")=-38
----------------------------------------------------*/
import java.util.Vector;
import java.util.Hashtable;
import java.util.Stack;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import com.jgwang.IDataFactory;
public class CalculatorA
{
protected IDataFactory varFactory; //当前语句的变量库
protected Hashtable localVarFact;
protected static Vector funct;
protected static Hashtable pri;
protected static String NOSOFunction="No so Function";
public static FastHashMap buildedStates;
static
{
funct=new Vector();
funct.addElement("+");
funct.addElement("-");
funct.addElement("*");
funct.addElement("/");
funct.addElement("(");
funct.addElement(")");
pri=new Hashtable();
pri.put("+","1");
pri.put("-","1");
pri.put("*","2");
pri.put("/","2");
pri.put("(","10");
pri.put(")","0");
buildedStates = new FastHashMap();
}
public CalculatorA()
{
varFactory = new VariableFactory();
}
public void setDataFactory(IDataFactory v)
{
this.varFactory = v;
}
public void setVariable(String param, String v)
{
if(this.varFactory==null)
varFactory = new VariableFactory();
varFactory.setVariable(param, v);
}
/*------------------------分析表达式---------------------------*/
public Vector analyseExp(String strExp)
{
boolean isStrBegin = false;
try
{
Vector strObjs = new Vector();
Vector obj = new Vector();
byte[] bExps = strExp.getBytes();
byte[] bExps1={'+'};
char qmark='\'';
if (strExp == null)
return null;
int isFunct = 0;
for(int i=0; i < bExps.length; i++)
{
int cPr=0;
bExps1[0]=bExps[i];
if((char)bExps1[0]=='"' || (char)bExps1[0]=='\'')
{
if(!isStrBegin) qmark = (char)bExps1[0];
obj.addElement(new Byte(bExps1[0]));
if(qmark == (char)bExps1[0])
isStrBegin = !isStrBegin;
continue;
}
else if(isStrBegin)
{
obj.addElement(new Byte(bExps1[0]));
continue;
}
if((char)bExps1[0]==' ') continue;
if (funct.indexOf(new String(bExps1))>=0)
{
if('('==(char)bExps1[0] && obj.size()>0)
{
obj.addElement(new Byte(bExps1[0]));
isFunct ++;
continue;
}
else if(')'==(char)bExps1[0] && isFunct>0)
{
obj.addElement(new Byte(bExps1[0]));
isFunct --;
continue;
}
if(isFunct==0)
{
if(obj.size()>0)
{
byte[] strObjBA= new byte[obj.size()];
for(int k=0; k<strObjBA.length ;k++)
strObjBA[k]=((Byte)obj.elementAt(k)).byteValue();
strObjs.addElement( new String(strObjBA));
}
if(obj.size()==0 && '-'==(char)bExps1[0])
strObjs.addElement("0");
strObjs.addElement(new String(bExps1));
obj.clear();
}
else
obj.addElement(new Byte(bExps1[0]));
}
else
{
obj.addElement(new Byte(bExps1[0]));
}
}
if(obj.size()>0)
{
byte[] strObjBA= new byte[obj.size()];
for(int k=0; k<strObjBA.length ;k++)
strObjBA[k]=((Byte)obj.elementAt(k)).byteValue();
strObjs.addElement( new String(strObjBA));
}
return strObjs;
}
catch(Exception e)
{
return null;
}
}
/*------------------------计算表达式的值---------------------------*/
public String calculateExp(String strExp) throws Exception
{
/*Vector strObjs = (Vector)buildedStates.get(strExp);
System.out.println(strObjs!=null?strObjs.toString():"");
if(strObjs==null)
{
strObjs = analyseExp(strExp);
//if(strObjs.size()>0)
buildedStates.put(strExp,analyseExp(strExp));
}
else if(strObjs.size()==1)
return getObjValue((String)strObjs.elementAt(0));*/
Vector strObjs = analyseExp(strExp);
Stack cacuObj = new Stack();
Stack cacuFunc = new Stack();
String strObj = "";
String value="";
int pr=0;
if(strObjs.size()==1)
{
strObj = (String)strObjs.elementAt(0);
if(strObj.startsWith("\"") || strObj.startsWith("'"))
strObj = getString(strObj);
return caculateValue(strObj,null,null);
}
for(int i=0; i<strObjs.size() ;i++)
{
strObj=(String)strObjs.elementAt(i);
if(strObj.startsWith("\"") || strObj.startsWith("'"))
strObj = getString(strObj);
if(funct.indexOf(strObj)>=0)
{
int cPr=Integer.parseInt((String)pri.get(strObj));
if(cPr>pr) {
cacuFunc.push(strObj);
if(cPr==10) pr=-1; else pr=cPr;
continue;
}
if(strObj.equals(")"))
{
if(pr==-1) cacuFunc.pop();
String f=(String)cacuFunc.pop();
while(!f.equals("("))
{
value=caculateValue((String)cacuObj.pop(),(String)cacuObj.pop(),f);
cacuObj.push(value);
f=(String)cacuFunc.pop();
}
if(cacuFunc.size()>0)
pr=Integer.parseInt((String)pri.get((String)cacuFunc.elementAt(cacuFunc.size()-1)));
else
pr=-1;
if(pr==10) pr=-1;
}
else
{
while(cPr<=pr)
{
if(cacuFunc.size()>0 && cacuObj.size()>1)
{
value=caculateValue((String)cacuObj.pop(),(String)cacuObj.pop(),(String)cacuFunc.pop());
cacuObj.push(value);
if(cacuFunc.size()>0)
pr=Integer.parseInt((String)pri.get((String)cacuFunc.elementAt(cacuFunc.size()-1)));
else
pr=-1;
}
else
pr=-1;
if(pr==10) pr=-1;
}
cacuFunc.push(strObj);
pr=cPr;
}
}
else
{
cacuObj.push(strObj);
}
if(i==strObjs.size()-1)
{
while(cacuFunc.size()>0 && cacuObj.size()>1)
{
value=caculateValue((String)cacuObj.pop(),(String)cacuObj.pop(),(String)cacuFunc.pop());
cacuObj.push(value);
}
}
}
return value;
}
/*------------------------计算操作符---------------------------*/
public String caculateValue(String strObj1,String strObj2,String cacuFunc) throws Exception
{
try
{
if(strObj1.indexOf("(")>0)
strObj1 = calcuFunction(strObj1);
strObj1 = getObjValue(strObj1);
if((strObj2==null)||(cacuFunc==null))
return strObj1;
if(strObj2.indexOf("(")>0)
strObj2 = calcuFunction(strObj2);
strObj2 = getObjValue(strObj2);
return cacuValue(strObj1,strObj2,cacuFunc);
}
catch(Exception e)
{
throw e;
}
}
public String cacuValue(String strObj1,String strObj2,String cacuFunc) throws Exception
{
double value=0;
try
{
//System.out.println(strObj2+cacuFunc+strObj1);
if(cacuFunc.equals("+") &&(!isNumber(strObj2) || !isNumber(strObj1)))
return strObj2+ strObj1;
if(strObj1.length()==0)
strObj1 = "0";
if(strObj2.length()==0)
strObj2 = "0";
if(cacuFunc.equals("+") )
value=Double.valueOf(strObj2).doubleValue()+Double.valueOf(strObj1).doubleValue();
else if(cacuFunc.equals("-"))
value=Double.valueOf(strObj2).doubleValue()-Double.valueOf(strObj1).doubleValue();
else if(cacuFunc.equals("*"))
value=Double.valueOf(strObj2).doubleValue()*Double.valueOf(strObj1).doubleValue();
else if(cacuFunc.equals("/"))
{
if(Double.valueOf(strObj1).doubleValue()!=0)
value=Double.valueOf(strObj2).doubleValue()/Double.valueOf(strObj1).doubleValue();
else value=0;
}
return String.valueOf(value);
}
catch(Exception e)
{
//System.out.print(e);
throw e;
}
}
public static boolean isNumber(String arg)
{
Pattern p=null; //正则表达式
Matcher m=null; //操作的字符串
p = Pattern.compile("\\-?\\d*\\.?\\d*[Ee]?\\d{0,3}");
m = p.matcher(arg);
return m.matches();
}
protected String getObjValue(String obj)
{
return obj;
}
/*------------------------计算函数---------------------------*/
public String calcuFunction(String functStatement) throws Exception
{
if(functStatement.toLowerCase().startsWith("str("))
{
String rv = functStatement.substring(4,functStatement.lastIndexOf(")"));
return rv.replaceFirst("['\"]","").replaceAll("['\"]$","");
}
String functName = functStatement.substring(0,functStatement.indexOf("("));
String statement = functStatement.substring(functStatement.indexOf("(")+1,functStatement.length()-1);
String[] args = split(functName,statement, ',');
for (int i=0; i<args.length; i++)
{
args[i] = calculateExp(args[i]);
}
String v = calcuFunctValue(functName, args);
return v;
}
protected String[] split(String functName, String v, char splitChar)
{
if(functName.equalsIgnoreCase("str"))
return new String[]{v};
StringBuffer objStr = new StringBuffer("");
int isFunct = 0;
for(int i=0; i < v.length(); i++)
{
if(v.charAt(i)=='(')
isFunct ++;
if(v.charAt(i)==')')
isFunct --;
if(v.charAt(i)==splitChar && isFunct==0)
objStr.append("&"+splitChar+"&");
else
objStr.append(v.charAt(i));
}
return new String(objStr).split("&"+splitChar+"&");
}
public String calcuFunctValue(String functName, String[] args) throws Exception
{
//functName = functName.toUpperCase();
if(functName.equalsIgnoreCase("str"))
{
return args[0];
}
else if(functName.equalsIgnoreCase("obj"))
{
return varFactory.getVariable(args[0]);
}
return extFunct(functName,args);
}
protected String extFunct(String functName, String[] args) throws Exception
{
throw new Exception("No so Function! " + functName);
}
public static String getString(String str)
{
return str.replaceFirst("['\"]","").replaceAll("['\"]$","");
}
public static void main(String argc[])
{
try{
CalculatorA dt =new CalculatorA();
String strExp=argc[0];//"(25+(10*10)-100)+(5-4)";
System.out.println(strExp+"="+dt.calculateExp(strExp));
}
catch(Exception e)
{
e.printStackTrace(System.out);
}
}
}
提供一个参考的方法,虽然原始,可以做一个自己的脚本语言解释器。
=========================================
//import java.util.*;
import com.jgwang.ITable;
import javax.servlet.http.HttpServletRequest;
import com.jgwang.ISysParamPool;
import com.jgwang.sys.Sys;
import com.jgwang.util.SysDate;
import com.jgwang.IPolynomial;
public class Polynomial extends CalculatorA implements IPolynomial
{
protected ITable table;
protected ISysParamPool sys;
protected HttpServletRequest request;
public Polynomial()
{
super();
}
public void setTable(ITable table)
{
this.table = table;
}
public void setSys(ISysParamPool sys)
{
this.sys = sys;
}
public void setRequest(HttpServletRequest request)
{
this.request = request;
}
public String transStateValueExt(String state) throws Exception
{
return transStateValue( state);
}
public String transStateValue(String state) throws Exception
{
if(state==null || state.length()==0)
return "";
//公式计算项目
while(state.indexOf("${")>=0 && state.indexOf("}")>=0)
{
String formula = "";
formula = state.substring(state.indexOf("${")+2,state.indexOf("}"));
String rv = calcuPolyn(formula);
state = state.substring(0,state.indexOf("${")) + rv
+ state.substring(state.indexOf("}")+1);
}
return state;
}
/* sample: IIF(FV(Status)=1:red , : ) IIF(bool:value,bool:value,:defaultValue)
字符串的几种表示方法 "string", 'string', str('string'), str("string"), str(无空格字符串),直接书写的无空格字符串
对于没有引号的字符串,系统会自动将空格去掉。对于长字符串,最好采用变量,然后在多项式中用obj(var)引用。
判断语句等于采用“=”号,对于赋值语句采用SQL语言格式的 set var=value;方式(LISP语言采用setq var=value;)。
对于对象操作,一律必须使用obj(object id)方式定义。
*/
public String calcuPolyn(String state) throws Exception
{
if(state.startsWith("set "))
{
String var = state.substring(4,state.indexOf("="));
String value = state.substring(state.indexOf("=")+1);
value =calcuPolyn(value);
varFactory.setVariable(var, value);
return value;
}
else if(state.startsWith("IIF"))
{
state = state.substring(4,state.lastIndexOf(")"));
String[] args = split("IIF",state,',');
for(int i=0; i<args.length; i++)
{
String[] st = split("IIF",args[i],':');
if(stateAnalye(st[0]))
return calculateExp(st[1]);
}
return "";
}
return calculateExp(state);
}
protected String extFunct(String functName, String[] args) throws Exception
{
if(functName.equalsIgnoreCase("FV"))
{
if(table==null)
return args[0];
return table.getValue(args[0]);
}
else if(functName.equalsIgnoreCase("Rqstobj"))
{
String v = request.getParameter(args[0]);
return v==null?"":Sys.toLocalStr(v);
}
else if(functName.equalsIgnoreCase("sysobj"))
{
String v = sys.getParam(args[0]);
return v==null?"":v;
}
else if(functName.equalsIgnoreCase("systime"))
{
return SysDate.getToday(args[0]);
}
else if(functName.equalsIgnoreCase("ord"))
{
String seq = args[0];
String fmt = args[1];
if(fmt.length()<seq.length())
return seq;
if(fmt.endsWith("d"))
return fmt.substring(0,fmt.length() - seq.length()) + seq;
else
return seq + fmt.substring(seq.length());
}
else if(functName.equalsIgnoreCase("replace"))
{
return args[0].replaceAll(args[1],args[2]);
}
else if(functName.equalsIgnoreCase("ADD"))
{
if(args.length<2)
return args[0];
return args[0]+args[1];
}
else if(functName.equalsIgnoreCase("MAX"))
{
double value = Double.valueOf(args[0] ).doubleValue();
for (int i=1; i<args.length; i++)
{
if(value<Double.valueOf(args[i] ).doubleValue()-0.0001)
value = Double.valueOf(args[i] ).doubleValue();
}
return String.valueOf(value);
}
else if(functName.equalsIgnoreCase("SMAX"))
{
String arg = args[0];
for (int i=1; i<args.length; i++)
{
if(args[i].compareTo(arg)>0)
arg = args[i];
}
return arg;
}
else if(functName.equalsIgnoreCase("Decimal"))
{
return args[0];
}
return "ERROR:"+functName;
}
protected boolean stateAnalye(String state) throws Exception
{
if(state.length()==0)
return true;
String funct = "=";
String[] states ;
if(state.indexOf(">=")>=0)
{
states = state.split(">=");
funct = ">=";
}
else if(state.indexOf("!=")>=0)
{
states = state.split("!=");
funct = "!=";
}
else if(state.indexOf("<=")>=0)
{
states = state.split("<=");
funct = "<=";
}
else
{
states = state.split("[>=<]");
if(state.indexOf(">")>=0) funct = ">";
if(state.indexOf("<")>=0) funct = "<";
}
if(states.length<2)
return false;
return compareState(states[0], states[1], funct);
}
protected boolean compareState(String obj1, String obj2, String funct) throws Exception
{
obj1 = calculateExp(obj1);
obj2 = calculateExp(obj2);
if(!isNumber(obj1) || !isNumber(obj2))
{
int rv = obj1.compareTo(obj2);
if(funct.equals("!=")) return rv!=0;
if(rv==0) return funct.indexOf("=")>=0;
if(rv<0) return funct.indexOf("<")>=0;
if(rv>0) return funct.indexOf(">")>=0;
return false;
}
else
{
if(obj1.length()==0) obj1 = "0";
if(obj2.length()==0) obj2 = "0";
double value1=Double.valueOf(obj1).doubleValue();
double value2=Double.valueOf(obj2).doubleValue();
if(funct.equals("=")) return Math.abs(value1-value2) < 0.001;
if(funct.equals(">=")) return value1-value2 >= -0.001;
if(funct.equals("<=")) return value1-value2 <= 0.001;
if(funct.equals(">")) return value1-value2 > 0.001;
if(funct.equals("<")) return value1-value2 < -0.001;
return false;
}
}
protected String getObjValue(String obj)
{
obj = super.getObjValue(obj);
return obj;
}
public static void main(String argc[])
{
try{
Polynomial dt =new Polynomial();
long begin =System.currentTimeMillis();
VariableFactory vf = new VariableFactory();
vf.setVariable("A","Select * from mis_rwe where a=");
vf.setVariable("B","150");
vf.setVariable("conf ","'5'");
dt.setDataFactory(vf);
dt.calcuPolyn("set A=IIF(obj(b)=150:add(obj(a)+obj(conf),str(\" order by desc\")),:空)");//strExp
dt.calcuPolyn("set A=str('新的变量值:')+obj(a)");//strExp
System.out.println(vf.getVariable("a"));
dt.calcuPolyn("set B=100");//strExp
dt.calcuPolyn("set A=IIF(obj(b)=100:str('(变更B变量后)')+obj(a),:空)");//strExp
System.out.println(vf.getVariable("a"));
dt.calcuPolyn("set A=replace(Obj(A),变更B变量后,str('替换函数操作后'))");//strExp
System.out.println(vf.getVariable("a"));
dt.calcuPolyn("set A=replace(\"测试 test\" + ' W J G ', test, newstr)");//strExp
System.out.println(vf.getVariable("a"));
for(int i=0; i<10;i++)
dt.calcuPolyn("set B=obj(b)+'100'");
System.out.println("B="+vf.getVariable("b"));
System.out.println("运行时间:"+(System.currentTimeMillis()-begin) +"毫秒");
}
catch(Exception e)
{
e.printStackTrace(System.out);
}
}
}