java实现四则运算的表达式逆波兰解析计算

逆波兰表达式又叫做后缀表达式。在通常的表达式中,二元运算符总是置于与之相关的两个运算对象之间,这种表示法也称为中缀表示。

正常的表达式 ---> 逆波兰表达式

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<String> expList = null;

	private List<String> 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<String>();
		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<String> getExpList()
	{
		return expList;
	}

	public void setExpList(List<String> expList)
	{
		this.expList = expList;
	}

	public List<String> getRpnList()
	{
		return rpnList;
	}

	public void setRpnList(List<String> 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<String> initRPN(List<String> strList)
	{
		List<String> returnList = new ArrayList<String>();
		//用来存放操作符的栈   
		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<String> 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<String> stackList = new LinkedList<String>();

		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"));
	}
}

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值