Java版Eval <转>

转自http://blog.csdn.net/laxsong/article/details/6873024 ,优化了负号的支持。 

原文中,对负号的支持不是太好,并且使用

  1. Double.toString(Double.parseDouble(d1)  
  2.                         / Double.parseDouble(d2)); 
  3. 在一些数据下运算可能会出现越界的情况。 
  4. 在此 也感谢 laxsong 的分享 。 

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Stack;

/**
 * Created by Heavenick on 2015/12/10.
 */
public class WinsonEval {
    private final static String ERR_NOT_END_VALID = "The last character of your expression MUST be '#'!";
    private final static String ERR_PARENTHESE_NOT_PAIR = "'(' & ')' should be used in pair!";
    private final static String ERR_CHAR_NOT_SUPPORT = "Not supported character";
    private final static String ERR_OPERATION_NOT_SUPPORTED = "Not supported operation";
    private final static String ERR_OPERATOR_NOT_VALID = " doesn't support double data!";
    private final static String ERR_UNKNOWN = "An unknown error!";

    private static boolean flag_double;

    /*
     * expression must be end with #
     */
    public static String eval(String expression) {

        ArrayList<String> list;
        try {
            list = toSuffixSequence(expression);
            System.out.println(list);
            return calculate(list);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static boolean isResultDouble() {
        return flag_double;
    }

    private static String calculate(ArrayList<String> list) throws Exception {
        Stack<String> stack = new Stack<String>();
        for (String s : list) {
            if (isOperator(s)) {
                String d1 = stack.pop();
                String d2 = stack.pop();
                String res = doCalc(d2, d1, s);
                stack.push(res);
            } else
                stack.push(s);
        }

        if (stack.size() == 1)
            return stack.pop();
        else
            throw new Exception(ERR_UNKNOWN);
    }

    private static String doCalc(String d1, String d2, String oper) throws Exception {
        if (oper != null && oper.length() > 1)
            throw new Exception(ERR_OPERATION_NOT_SUPPORTED + ":'" + oper + "'");

        switch (oper.charAt(0)) {
            case '+':
                return new BigDecimal(d1).add(new BigDecimal(d2)).toPlainString();
            case '-':
                return new BigDecimal(d1).subtract(new BigDecimal(d2)).toPlainString();
            case '*':
                return new BigDecimal(d1).multiply(new BigDecimal(d2)).toPlainString();
            case '/':
                return new DecimalFormat("####.#").format(new BigDecimal(d1).divide(new BigDecimal(d2),4,BigDecimal.ROUND_HALF_UP).doubleValue());
            case '%':
                return new BigDecimal(d1).divideAndRemainder(new BigDecimal(d2))[0].toPlainString();
            default:
                throw new Exception(ERR_OPERATION_NOT_SUPPORTED + ":'" + oper + "'");
        }
    }

    private static boolean isDoubleNeeded(String d1, String d2, String oper) {
        if (d1.contains(".") || d2.contains("."))
            return true;
        if (oper != null && oper.equals("/")) {
            int left = Integer.parseInt(d1) % Integer.parseInt(d2);
            if (left != 0)
                return true;
        }
        return false;
    }

    private static boolean isOperator(String str) {
        if (str != null
                && (str.equals("+") || str.equals("-") || str.equals("*")
                || str.equals("/") || str.equals("%")))
            return true;
        return false;
    }

    private static ArrayList<String> toSuffixSequence(String expression)
            throws Exception {

        if (!expression.endsWith("#"))
            throw new Exception(ERR_NOT_END_VALID);

        ArrayList<String> list = new ArrayList<String>();
        Stack<String> stack = new Stack<String>();
        stack.push("#");
        char last, ch;
        StringBuffer sb = null;
        for (int i = 0; i < expression.length(); i++) {
            ch = expression.charAt(i);
            switch (ch) {

                case '+':
                case '-':
                case '*':
                case '/':
                case '%':
                    last = stack.peek().charAt(0);

                    //TODO  如果当前字符不是“-” 并且前一个不是运算符,或者堆里面的数据数大于等于2个,才将 运算符压入堆中
                    if( ! ( ch == '-' && isOperator(last+"") ) ||  list.size() >=2 ) {
                        if (last != '(' && priority(last) >= priority(ch))
                            list.add(stack.pop());
                    }
                    stack.push("" + ch);
                    break;
                case '(':
                    stack.push("(");
                    break;
                case ')':
                    while (!stack.isEmpty() && stack.peek().charAt(0) != '(')
                        list.add(stack.pop());
                    if (stack.isEmpty() || stack.size() == 1)
                        throw new Exception(ERR_PARENTHESE_NOT_PAIR);
                    stack.pop();
                    break;
                case '#':
                    while (stack.size() > 1 && stack.peek().charAt(0) != '(')
                        list.add(stack.pop());
                    if (stack.size() > 1)
                        throw new Exception(ERR_PARENTHESE_NOT_PAIR);
                    break;
                default:
                    if (Character.isDigit(ch) || '.' == ch) {
                        sb = new StringBuffer();
                        sb.append(ch);
                        while (Character.isDigit(expression.charAt(i + 1)) || expression.charAt(i + 1) == '.')
                            sb.append(expression.charAt(++i));

                        String ls = stack.pop();
                        String n = sb.toString();

                        // 如果前一个字符是“-” 将进行判断,是不是负号
                        if("-".equals(ls)){
                            if( ("#".equals(stack.peek()) && list.size() == 0) || (isOperator(stack.peek()) )) {
                                n = "-" + n;
                            }else{
                                stack.push("-");
                            }
                        }else{
                            stack.push(ls);
                        }

                        list.add(n);

                        break;
                    } else
                        throw new Exception(ERR_CHAR_NOT_SUPPORT + ":'" + ch + "'");

            }
        }
        return list;
    }

    private static int priority(char ch) {
        switch (ch) {
            case '+':
            case '-':
                return 1;
            case '*':
            case '/':
            case '%':
                return 2;
            case '#':
                return 0;
            default:
                return 0;
        }
    }

    public static void main(String[] args) {
        String expression = "2+-7#";
        try {
            System.out.println(WinsonEval.eval("(2*2+6)/5+3#").toString());
            System.out.println(WinsonEval.eval("2+-7#"));
            System.out.println(WinsonEval.eval("2-7#"));
            System.out.println(WinsonEval.eval("-2+7#"));
            System.out.println(WinsonEval.eval("3/6#"));
            System.out.println(WinsonEval.eval("3/2#"));
            System.out.println(WinsonEval.eval("2/3#"));
            System.out.println(WinsonEval.eval("12*15.12-12#"));
            System.out.println(WinsonEval.eval("(2*-2+6)/5+3#"));

//            && !StringUtils.containsAny(stack.peek(),new char[]{'*','/'})
        } catch (Exception e) {
            e.printStackTrace();
        }

//      System.out.println(Character.getType('.'));
//      System.out.println(Character.getType('1'));
    }


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值