读书人

java解析四则运算+-/()字符串表达式,并

发布时间: 2012-12-20 09:53:21 作者: rapoo

java解析四则运算+-*/()字符串表达式,并按照精度进行计算结果,还提供按精度比较的方法

前言:最近涉及到业务人员配置数学表达式,要求解析并按照精度进行计算

?

参考了如下百度百科对逆波兰算法的讲解进行开发,开发过程中还参考了一篇精度算法的文章

1:http://baike.baidu.com/view/552648.htm

2:还有一遍文章忘了链接了,如果侵犯作者权利请告知,我立即删除

?

该类支持精度计算,支持负数,精度比较等功能。计算按照逆波兰方式解析。

?

/** * @Project:      BizRule      * @File:         org.coffeesweet.util.MathExpress.java * @Author:       coffeesweet * @Date:         2011-3-28 * @Description:  2011 coffeesweet Inc. All rights reserved. */package org.coffeesweet.util;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 coffeesweet * +,-,*,/四则运算的表达式逆波兰解析计算类,精确计算,应用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 OP6 = "%";    /**     * (     */    private final static String OPSTART = "(";           /**     * )     */    private final static String OPEND = ")";        /**     * !用来替代负数前面的'-'     *///    private final static String NEGATIVESING = "!";        /**     * !用来替代负数前面的'+'     *///    private final static String PLUSSING = "@";        /**     * '#'用来代表运算级别最低的特殊字符     *///    private final static String LOWESTSING = "#";       //最原始的四则运算式    private String expBase;        //经过初始化处理后的四则运算式    private String expInited;           //精度    private int precision=10;           //取舍模式    private RoundingMode roundingMode=RoundingMode.HALF_UP;        //精度上下文    private MathContext mc;           //四则运算解析    private List<String> expList = new ArrayList<String>();       //存放逆波兰表达式    private List<String> rpnList = new ArrayList<String>();        public MathExpress(){    }        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);    while(st.hasMoreElements()){    this.expList.add(st.nextElement().toString().trim());    }        this.rpnList = initRPN(this.expList);        }        /** * @return the expBase */public String getExpBase() {return expBase;}/** * @param expBase the expBase to set */public void setExpBase(String expBase) {this.expBase = expBase;}/** * @return the expInited */public String getExpInited() {return expInited;}/** * @param expInited the expInited to set */public void setExpInited(String expInited) {this.expInited = expInited;}/** * @return the precision */public int getPrecision() {return precision;}/** * @param precision the precision to set */public void setPrecision(int precision) {this.precision = precision;}/** * @return the roundingMode */public RoundingMode getRoundingMode() {return roundingMode;}/** * @param roundingMode the roundingMode to set */public void setRoundingMode(RoundingMode roundingMode) {this.roundingMode = roundingMode;}/** * @return the expList */public List<String> getExpList() {return expList;}/** * @param expList the expList to set */public void setExpList(List<String> expList) {this.expList = expList;}/** * @return the rpnList */public List<String> getRpnList() {return rpnList;}/** * @param rpnList the rpnList to set */public void setRpnList(List<String> rpnList) {this.rpnList = rpnList;}/** * @return the mc */public MathContext getMc() {return mc;}/** * @param mc the mc to set */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 tempNumber2 = new BigDecimal(numberStack.pop(),this.mc);                                   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);                   }                  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 static 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;    }        public static void main(String...args){//    MathExpress me = new MathExpress("-(-0.5+0.1)*10+2",10,RoundingMode.HALF_UP);//    System.out.println(me.getExpList());//    List<String> tempList = me.initRPN(me.getExpList());//    System.out.println(tempList);//    String resultStr = me.caculate(tempList);//    System.out.println(resultStr);        MathExpress me = new MathExpress("-(-1.5000000003+0.1)*10+2");    String resultStr = me.caculate();    BigDecimal bd = new BigDecimal(resultStr);    BigDecimal bd2 = bd.setScale(2, RoundingMode.HALF_UP);    System.out.println(me.caculate());    System.out.println(bd.toString());    System.out.println(bd.scale());    System.out.println(bd2.toString());    System.out.println(bd2.scale());    //    System.out.println("------------------------------------");//    Pattern p = Pattern.compile("^\\([\\s\\S]*\\)$");//匹配类似以'('开头')'结尾的字符串//    Matcher m = p.matcher("(2.  0>2.22)");//    System.out.println(m.matches());        boolean reBoolean = MathExpress.compareTo("((-8.0+3)>=2. 1)");    System.out.println(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();        }    }}

?

读书人网 >编程

热点推荐