逆波兰表达式又叫做后缀表达式。在通常的表达式中,二元运算符总是置于与之相关的两个运算对象之间,这种表示法也称为中缀表示。
正常的表达式 ---> 逆波兰表达式
a+b ---> a,b,+
a+(b-c) ---> a,b,c,-,+
a+(b-c)*d ---> a,b,c,-,d,*,+
a+d*(b-c)--->a,d,b,c,-,*,+
a=1+3 ---> a,1,3,+,=
以下为java解析:
package com.tp.test.formula;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author
* +,-,*,/四则运算的表达式逆波兰解析计算类,精确计算,应用BigDecimal类处理
* 支持负数,但规范除整个表达式第一个数为负数时可以不出现在'('后,其它表达式中间任何位置的
* 负数必须出现在'('后,即:用括号括起来。比如:-3+(-2+1)*10或-3+((-2)+1)*10或(-3)+(-2+1)*10或(-3)+((-2)+1)*10
*/
public class MathExpress
{
private final static String OP1 = "+";
private final static String OP2 = "-";
private final static String OP3 = "*";
private final static String OP4 = "/";
private final static String OP5 = "%";
private final static String OPSTART = "(";
private final static String OPEND = ")";
private String expBase;
private String expInited;
private int precision = 4;
private RoundingMode roundingMode = RoundingMode.HALF_UP;
private MathContext mc;
private List expList = null;
private List rpnList = null;
public MathExpress()
{
}
public String caculateFormula(String expBase)
{
return caculateFormula(expBase, precision, roundingMode);
}
public String caculateFormula(String expBase, int precision, RoundingMode roundingMode)
{
init(expBase, precision, roundingMode);
return caculate();
}
public MathExpress(String expBase)
{
init(expBase, this.precision, this.roundingMode);
}
public MathExpress(String expBase, int precision, RoundingMode roundingMode)
{
init(expBase, precision, roundingMode);
}
public void init(String expBase, int precision, RoundingMode roundingMode)
{
this.expBase = expBase;
this.precision = precision;
this.roundingMode = roundingMode;
this.mc = new MathContext(precision, roundingMode);
this.expInited = initExpress(expBase);
StringTokenizer st = new StringTokenizer(this.expInited, "+-*/^%()", true);
this.expList = new ArrayList();
while (st.hasMoreElements())
{
this.expList.add(st.nextElement().toString().trim());
}
this.rpnList = initRPN(this.expList);
}
public String getExpBase()
{
return expBase;
}
public void setExpBase(String expBase)
{
this.expBase = expBase;
}
public String getExpInited()
{
return expInited;
}
public void setExpInited(String expInited)
{
this.expInited = expInited;
}
public int getPrecision()
{
return precision;
}
public void setPrecision(int precision)
{
this.precision = precision;
}
public RoundingMode getRoundingMode()
{
return roundingMode;
}
public void setRoundingMode(RoundingMode roundingMode)
{
this.roundingMode = roundingMode;
}
public List getExpList()
{
return expList;
}
public void setExpList(List expList)
{
this.expList = expList;
}
public List getRpnList()
{
return rpnList;
}
public void setRpnList(List rpnList)
{
this.rpnList = rpnList;
}
public MathContext getMc()
{
return mc;
}
public void setMc(MathContext mc)
{
this.mc = mc;
}
/**
* 去除空白字符和在负号'-'前加'0',便于后面的StringTokenizer
* @param exp
* @return
*/
private static String initExpress(String exp)
{
String reStr = null;
reStr = exp.replaceAll("\\s", "");
if (reStr.startsWith("-"))
{
reStr = "0" + reStr;
}
reStr = reStr.replaceAll("\\(\\-", "(0-");
return reStr;
}
/**
* 是否是整数或是浮点数,但默认-05.15这种也认为是正确的格式
* @param str
* @return
*/
private boolean isNumber(String str)
{
Pattern p = Pattern.compile("^(-?\\d+)(\\.\\d+)?$");
Matcher m = p.matcher(str);
boolean isNumber = m.matches();
return isNumber;
}
/**
* 设置优先级顺序()设置与否无所谓
* @param sign
* @return
*/
private int precedence(String str)
{
char sign = str.charAt(0);
switch (sign)
{
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
case '^':
case '%':
return 3;
case '(':
case ')':
// case '#':
default:
return 0;
}
}
/**
* 转变为逆波兰表达式
* @param strList
* @return
*/
public List initRPN(List strList)
{
List returnList = new ArrayList();
//用来存放操作符的栈
Stack stack = new Stack();
// stack.push(LOWESTSING);
int length = strList.size();
for (int i = 0; i < length; i++)
{
String str = strList.get(i);
if (isNumber(str))
{
returnList.add(str);
}
else
{
if (str.equals(OPSTART))
{
//'('直接入栈
stack.push(str);
}
else if (str.equals(OPEND))
{
//')'
//进行出栈操作,直到栈为空或者遇到第一个左括号
while (!stack.isEmpty())
{
//将栈顶字符串做出栈操作
String tempC = stack.pop();
if (!tempC.equals(OPSTART))
{
//如果不是左括号,则将字符串直接放到逆波兰链表的最后
returnList.add(tempC);
}
else
{
//如果是左括号,退出循环操作
break;
}
}
}
else
{
if (stack.isEmpty())
{
//如果栈内为空
//将当前字符串直接压栈
stack.push(str);
}
else
{
//栈不空,比较运算符优先级顺序
if (precedence(stack.top()) >= precedence(str))
{
//如果栈顶元素优先级大于当前元素优先级则
while (!stack.isEmpty() && precedence(stack.top()) >= precedence(str))
{
returnList.add(stack.pop());
}
}
stack.push(str);
}
}
}
}
//如果栈不为空,则将栈中所有元素出栈放到逆波兰链表的最后
while (!stack.isEmpty())
{
returnList.add(stack.pop());
}
return returnList;
}
/**
* 计算逆波兰表达式
* @param rpnList
* @return
*/
public String caculate(List rpnList)
{
Stack numberStack = new Stack();
int length = rpnList.size();
for (int i = 0; i < length; i++)
{
String temp = rpnList.get(i);
if (isNumber(temp))
{
numberStack.push(temp);
}
else
{
// BigDecimal tempNumber1 = new BigDecimal(numberStack.pop(), this.mc);
BigDecimal tempNumber1 = new BigDecimal(numberStack.pop());
// BigDecimal tempNumber2 = new BigDecimal(numberStack.pop(), this.mc);
BigDecimal tempNumber2 = new BigDecimal(numberStack.pop());
BigDecimal tempNumber = new BigDecimal("0", this.mc);
if (temp.equals(OP1))
{
tempNumber = tempNumber2.add(tempNumber1);
}
else if (temp.equals(OP2))
{
tempNumber = tempNumber2.subtract(tempNumber1);
}
else if (temp.equals(OP3))
{
tempNumber = tempNumber2.multiply(tempNumber1);
}
else if (temp.equals(OP4))
{
tempNumber = tempNumber2.divide(tempNumber1, precision, roundingMode);
}
else if(temp.equals(OP5))
{
tempNumber = tempNumber2.divideAndRemainder(tempNumber1)[1];
}
numberStack.push(tempNumber.toString());
}
}
return numberStack.pop();
}
/**
* 按照类的缺省参数进行计算
* @return
*/
public String caculate()
{
return caculate(this.rpnList);
}
/**
* 数字条件表达式精确比较
* eg: "3.0>2" "1<5" "1==5" "1!=5" "(1.0+2)>3" "((-0.9+3)>=2. 1)"
* 不支持&&,||等连接符
* @param str
* @return
*/
public boolean compareTo(String strParm)
{
boolean reBoolean = false;
boolean isParentheses = false;//标记是否有()括上整个字符串
String str = initExpress(strParm);
Pattern p = Pattern.compile("^\\([\\s\\S]*\\)$");
Matcher m = p.matcher(str);
isParentheses = m.matches();
if (-1 == str.indexOf(">=") && -1 == str.indexOf("<=") && -1 == str.indexOf("==") && -1 == str.indexOf("!="))
{
if (-1 == str.indexOf(">") && -1 == str.indexOf("<"))
throw new IllegalArgumentException("异常:条件表达式不正确!");
}
if (-1 != str.indexOf(">="))
{
String[] strTemps = str.split(">=");
if (isParentheses)
{
strTemps[0] = strTemps[0] + ")";
strTemps[1] = "(" + strTemps[1];
}
int r = new BigDecimal((new MathExpress(strTemps[0]).caculate())).compareTo(new BigDecimal((new MathExpress(strTemps[1]).caculate())));
if (-1 == r)
{
reBoolean = false;
}
else
{
reBoolean = true;
}
}
else if (-1 != str.indexOf("<="))
{
String[] strTemps = str.split("<=");
if (isParentheses)
{
strTemps[0] = strTemps[0] + ")";
strTemps[1] = "(" + strTemps[1];
}
int r = new BigDecimal((new MathExpress(strTemps[0]).caculate())).compareTo(new BigDecimal((new MathExpress(strTemps[1]).caculate())));
if (1 == r)
{
reBoolean = false;
}
else
{
reBoolean = true;
}
}
else if (-1 != str.indexOf("=="))
{
String[] strTemps = str.split("==");
if (isParentheses)
{
strTemps[0] = strTemps[0] + ")";
strTemps[1] = "(" + strTemps[1];
}
int r = new BigDecimal((new MathExpress(strTemps[0]).caculate())).compareTo(new BigDecimal((new MathExpress(strTemps[1]).caculate())));
if (0 == r)
{
reBoolean = true;
}
else
{
reBoolean = false;
}
}
else if (-1 != str.indexOf("!="))
{
String[] strTemps = str.split("!=");
if (isParentheses)
{
strTemps[0] = strTemps[0] + ")";
strTemps[1] = "(" + strTemps[1];
}
int r = new BigDecimal((new MathExpress(strTemps[0]).caculate())).compareTo(new BigDecimal((new MathExpress(strTemps[1]).caculate())));
if (0 != r)
{
reBoolean = true;
}
else
{
reBoolean = false;
}
}
else if ((-1 != str.indexOf(">")) && (-1 == str.indexOf("=")))
{
String[] strTemps = str.split(">");
if (isParentheses)
{
strTemps[0] = strTemps[0] + ")";
strTemps[1] = "(" + strTemps[1];
}
int r = new BigDecimal((new MathExpress(strTemps[0]).caculate())).compareTo(new BigDecimal((new MathExpress(strTemps[1]).caculate())));
if (1 == r)
{
reBoolean = true;
}
else
{
reBoolean = false;
}
}
else if ((-1 != str.indexOf("<")) && (-1 == str.indexOf("=")))
{
String[] strTemps = str.split("<");
if (isParentheses)
{
strTemps[0] = strTemps[0] + ")";
strTemps[1] = "(" + strTemps[1];
}
int r = new BigDecimal((new MathExpress(strTemps[0]).caculate())).compareTo(new BigDecimal((new MathExpress(strTemps[1]).caculate())));
if (-1 == r)
{
reBoolean = true;
}
else
{
reBoolean = false;
}
}
return reBoolean;
}
private class Stack
{
LinkedList stackList = new LinkedList();
public Stack()
{
}
/**
* 入栈
* @param expression
*/
public void push(String expression)
{
stackList.addLast(expression);
}
/**
* 出栈
* @return
*/
public String pop()
{
return stackList.removeLast();
}
/**
* 栈顶元素
* @return
*/
public String top()
{
return stackList.getLast();
}
/**
* 栈是否为空
* @return
*/
public boolean isEmpty()
{
return stackList.isEmpty();
}
}
public static void main(String[] args) {
MathExpress operator = new MathExpress();
System.out.println(operator.caculateFormula("25*(6.55-1.2)+20*2"));
}
}