Java双栈算式解释器

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java双栈算式解释器相关的知识,希望对你有一定的参考价值。

import java.util.Stack;
// 


import java.util.regex.*;
import java.util.Stack;

/**
 * This class use for get calculate result from the String expression
 * we know that Java language have not class implement method calculate math 
 * expression, javascript have implement "eval".
 * First get simple math expression, iteration wipe out brackets, get expression
 * in brackets and format with priority, then insert result of formative expression 
 * into original expression, and simplify again
 * 
 * Support operator "+", "-", "*", "/", "(", ")", "(-)"
 * use Stack.RegEx
 * 
 * @author Denua
 * @version 07 May 2017 11.48
 */
public class Interpreter {

    public static void main(String[] args) {
        
        String s = "(1+2)-3*5+(5/5*5+5)-1/2";
        Interpreter in = new Interpreter();
        System.out.printf("%s = %g",s,in.elv(s));
    }
    /**
     * public method as the entry
     * @param str 
     *             String expression
     * @return
     *         double calculate result
     */
    public double elv(String str){
        
        double res = 0.00;
        res = eval(formate(
                       getSimple(str)                        
                  )
              );    
        return res;
    }
    /**
     * return String simple expression without brackets,use RegEx check brackets and get 
     * result from the expression in the brackets
     * @param str 
     *             String  complex expression
     * @return String 
     *             String simple expression
     */
    private String getSimple(String str){
        
        String res = str;
        // RegEx matching the expression in brackets
        Pattern pat2 = Pattern.compile("\\([\\d\\.\\+\\-\\*\\/]+\\)");
        // matching 
        Matcher mat = pat2.matcher(str);
        // if find matching, get simple expression result and joint to origin expression
        if( mat.find() ){
            String find = mat.group(0);
            String st1 = res.substring(0, str.indexOf(find));    
            String st2 = res.substring(str.indexOf(find) + find.length(), res.length());
            
            find = find.substring(1, find.length() - 1);
            find = formate(find);
            find = String.valueOf(eval(find));

            res = st1 + find + st2; 
            // matching again and find expression in brackets, if find, get simple expression
            Matcher mat2 = pat2.matcher(res);
            if(mat2.find()){
                res = getSimple(res);
            }
        }
        return res;
    }
    /**
     * add brackets for the simple String expression, complete priority, check
     *  each element in the expression 
     * 
     * @param str 
     *             String simple  expression
     * @return String 
     *             complete priority expression 
     */
    private String formate(String str){
        
        String res = str;
        String[][] part = getPart(res);
        String[] pt = new String[part[0].length];
        
        for(int q=0; q < pt.length; q++){
            pt[q] = "";
        }
        
        int count = part[0].length;
        int i = 0;
        
//  all case in priority
//         (*)    *     
//         (+)    +
     
//         (*)    +
//         (+)    *
        
//         +    *  (*)    +
//         * (*)    +
        
        while( i < count){

            String id= part[0][i];
            String ir = null;
            if(i < count - 1)
                ir = part[0][i + 1];

            if( nl(id) && nl(ir) ){
                
                if( isf(id) ){
                    
                    if( isf(ir) ){
                        pt[i+1] += ")";
                    }
                    else if( ! isf(ir) ){
                        pt[i+1] += ")";                        
                        int idx = i - 1;
                        
                        while( idx >= 0 ){
                            String si = part[0][idx];
                            if( ! isf(si) ){
                                pt[i+1] = "))";
                                break;
                            }
                            idx--;
                        }        
                    }
                }
                if( ! isf(id) ){
                    
                     if( ! isf(ir) )
                        pt[i+1] += ")";    
                }                
            }
            else if( nl(id) && ! nl(ir)){
                
                if( isf(id) ){                    
                    int ix = i - 1;
                    boolean find = false;
                    
                    while( ix >= 0 ){
                        String six = part[0][ix];
                        if( ! isf(six) ){
                            find = true;                            
                            break;
                        }
                        ix--;
                    }
                    if(find)
                        part[1][i+1] += "))";
                    else
                        part[1][i + 1] += ")";
                }
                else
                    part[1][i + 1] += ")";
            }
            else{
                return null;
            }                        
            i++;
        }
        res = "";
        for(int j = 0; j < part[0].length; j ++){
            part[0][j] = pt[j] + part[0][j];
            res =res + part[1][j] + part[0][j];
        }
        res += part[1][part[1].length -1];
        
        return res;
    }
    /**
     *  use two Stack calculate expression with complete priority, one Stack
     *  save number another save operator, check each element in the expression
     *  with complete priority, if current element is number, then add to 
     *  number Stack, if operator, add to operator Stack, else is ")" ,  extract
     *  two number from the number Stack, extract operator from the operator Stack
     *  and add result to number Stack, iteration get final result.
     * 
     * @param str 
     *             Complete priority expression
     * @return double 
     *             the result of the expression
     */
    private Double eval(String str){
        
        Stack<String> operate = new Stack<String>();
        Stack<Double> value = new Stack<Double>();
        
        String[] ele = getEle(str);
        
        int i = 0;
        while( i < ele.length){

            String s = ele[i];
            if(s.equals("(")){
            }
            else if(s.equals("+"))        operate.push(s)    ;
            
            else if(s.equals("-"))        operate.push(s) ;

            else if(s.equals("*"))        operate.push(s)    ;

            else if(s.equals("/"))        operate.push(s)    ;

            else if(s.equals("s"))        operate.push(s)    ;

            else if(s.equals(")")){
                
                String op = operate.pop();
                double vl = value.pop();
                
                if(op.equals("+"))            vl = value.pop() + vl;
                
                else if(op.equals("-"))        vl = value.pop() - vl;
                
                else if(op.equals("*"))        vl = value.pop() * vl;
                
                else if(op.equals("/"))        vl = value.pop() / vl;
                
                else if(op.equals("s"))    vl = Math.sqrt(vl);
                
                value.push(vl);
            }
            else{
                value.push(Double.parseDouble(s));
            }            
            i++;
        }
        return value.pop();
    }
    /**
     * get each part of the expression, cut expression and transform to Array
     * @param str complete priority expression
     * @return String[] 
     */
    private String[] getEle(String str){
        
        Stack<String> st = new Stack<String>();
        
        int j = 0;
        String numbTemp = "";
        while( j < str.length()){
            char temp = str.charAt(j);
            if( isNum(temp) || temp == ‘.‘ || ( j == 0 && temp == ‘-‘) || ( temp == ‘-‘ && isOp(str.charAt(j - 1)) ) ){                
                numbTemp += temp;
            }
            else if( ! isNum(temp)  ){
                if( !numbTemp.isEmpty()){
                    st.push(numbTemp);
                    numbTemp = "";
                }
                st.push(String.valueOf(temp));
            }
            j++;
        }
        
        String[] res = new String[st.size()];
        for(int i = st.size() - 1; i >= 0; i -- ){
            res[i] = st.pop();
        }
        return res;
    }
    private String[][] getPart(String str){
        
        String res = str;        
        int i = 0;
        Stack<String> cal = new Stack<String>();
        Stack<String> op = new Stack<String>();
        
        String num = "";
        while( i < res.length()){
            char temp = res.charAt(i);            
            if( isOp(temp) ){
                if(temp == ‘-‘ && i == 0)
                    num += "-";
                else if( temp == ‘-‘ && isOp(res.charAt(i-1)) )
                    num += "-";
                else
                    op.push(String.valueOf(temp));
            }
            else if(isNum(temp)){
                num += String.valueOf(temp);
                if(i >= str.length()){
                    break;
                }
                else{
                    if( i == str.length() - 1){
                        
                        String n = String.valueOf(str.charAt(i));
                        if( isNum(n) && isNum(String.valueOf(str.charAt(i-1)))){
                            num += n;
                        }
                        else{
                            num = n;
                        }
                    }
                    else{
                        String n = String.valueOf(str.charAt(i + 1));
                        boolean flag = true;
                        while( isNum(n) && flag){                        
                            num += n;
                            i ++;
                            
                            if( i > res.length() - 2){
                                flag = false;
                            }else{
                                n = String.valueOf(str.charAt(i + 1));
                            }
                        }
                    }                    
                }
                cal.push(num);
                num = "";
            }
            else if(temp == ‘)‘){        
                op.push(")");
            }
            i++;
        }
        i = 0;
        
        String[][] part = new String[2][];
        String[] temp1 = new String[op.size()];
        String[] temp2 = new String[cal.size()];
        for(Object o:op.toArray()){
            temp1[i] = (String) o;
            i++;            
        }
        i = 0;
        for(Object o:cal.toArray()){
            temp2[i] = (String) o;
            i++;            
        }
        
        part[0] = temp1;
        part[1] = temp2;
        
        return part;
        
    }
    private boolean isNum(String str){
        return  str.equals("0") || str.equals("1") || str.equals("2") || str.equals("3") || str.equals("4") ||
                str.equals("5") || str.equals("6") || str.equals("7") || str.equals("8") || str.equals("9") || str.equals(".");
    }
    private boolean isOp(char str){        
        return str == ‘s‘ || str == ‘+‘  ||str == ‘-‘  || str == ‘*‘  || str == ‘/‘ ;
    }
    private boolean isNum(char str){
        return  str == ‘0‘  || str == ‘1‘ || str == ‘2‘  || str == ‘3‘  || str == ‘4‘  ||
                str == ‘5‘  || str == ‘6‘  || str == ‘7‘  || str == ‘8‘  || str == ‘9‘ || str == ‘.‘  ;
    }    
    private boolean isf(String str){
        return str.equals("*") || str.equals("/");
    }
    private boolean nl(Object obj){
        return obj != null;
    }
}


本文出自 “12883274” 博客,请务必保留此出处http://12893274.blog.51cto.com/12883274/1922908

以上是关于Java双栈算式解释器的主要内容,如果未能解决你的问题,请参考以下文章

在java中编写九九乘法表的程序,重要的是帮忙解释一下!

双栈完全解决计算器问题

C++实现一个简单的双栈队列

解释器模式

Linux读写执行权限的二进制解释

nodejs REPL 初步