输入一个运算表达式  
如:12+100*3-50/5
判断表达式的正确性,如果正确,并求值....

解决方案 »

  1.   

    如果不正确,应该会抛出SQLException
      

  2.   

    不知道java有没有eval这样功能的方法
      

  3.   

    这个东西用词法分析最好,不过我不太懂编译原理。只好笨办法了。另外附送一个功能,处理括号。import java.util.LinkedList;
    import java.util.List;
    /**
     * 这个类用来包装一段仅包括数字,+-/*和小数点.的字符串。
     * 由于正则式写的比较简单,所以不支持负号-,所有的-都被认为是减号。
     * 该类在计算表达式的时候遵循的策略是先将高优先级的运算(*与/)计算完毕再进行+-运算。
     * 比如 1+3+4*5+4/2,该类具体计算过程为 
     * 1、先分解表达式,存为两个list "134542"和"++*+/",并纪录高优先级运算符数量为2
     * 2、在存运算符的list的size不为0的情况下,将高优先级的运算计算 即先算 4*5 ,然后再 4/2 ,把式子转成1+3+20+2
     * 3、依次计算全部是+-运算的式子
     */
    class Formula{
        
        private List<Double> listNumbers; //这个list纪录所有的要计算的值
        private List<String> listOperator; //这个list纪录所有的操作符
        private int highOperateNum = 0;     //这个值标记着当前还有多少高级别的操作符,将会优先计算这些运算符相关的式子。
        
        Formula(String strOri){
         //由于在计算过程中,在计算一个式子后,需要更新list,用LinkedList比较好。
            listNumbers = new LinkedList<Double>(); 
            listOperator = new LinkedList<String>();         this.formatOri(strOri);         
        }
        
        /**
         * @param strOri 目标字符串
         * 这个方法用来将字符串分解,注意这里没有验证字符串的有效性。
         * 如果要添加对符号的支持,请修改这个方法中的具体实现。
         */
        private void formatOri(String strOri){
            
            String[] numTemp;
            String[] optTemp;
            
            numTemp = strOri.split("[\\+\\-\\*/]") ; //根据+-*/号分解字符串,
            for(int i=0 ; i<numTemp.length ; i++){
                listNumbers.add(Double.valueOf(numTemp[i]));
            }        
            
            optTemp = strOri.split("[0-9\\.]+");//根据数字和小数点分解字符串
            for(int i=1 ; i<optTemp.length ; i++){        
                listOperator.add(optTemp[i]);
                if (optTemp[i].equals("*") || optTemp[i].equals("/")){
                  this.highOperateNum++ ;
                }
            }
        }
        
        public static void main(String args[]){
            Formula f = new Formula("1*3+5+5*6/8-23+6+14+12*3-6*4"); //3+5+3.75-23+6+14+36-24 =20.75
            System.out.println(f.getValue());
        }
        
        public double getValue(){
        
         int firstHigh=0 ; //这个参数用来临时存储找出来第一个高优先级操作符的索引值
            while (this.listOperator.size() > 0 ){ //如果操作符列表还有值代表运算没有最终完成
            
             if (this.highOperateNum>0){ //如果高优先值运算符的数量不为0,就先根据高优先级运算符计算
        
    firstHigh = this.listOperator.indexOf("*");   //尝试寻找第一个*的index
    firstHigh = (firstHigh==-1?this.listOperator.indexOf("/"):firstHigh) ;//防止只剩下除法

    if (firstHigh == -1) return Double.NaN;   //this.highOperateNum>0时,firstHigh不应该为0

    this.perpareReckon(firstHigh);  //尝试计算         }else{
             this.reckon(0); //直接计算
             }        
            }  
        
    return this.listNumbers.get(0).doubleValue();    
        }    /**
         * @param index 表明要尝试计算的运算符位置.
         * 该方法主要为了处理当前运算符为*,但是前面还有个/的及类似的情况(递归调用perpareReckon(index-1))
         */
        private void perpareReckon(int index){
        
            if (this.listOperator.get(index).equals("*")||this.listOperator.get(index).equals("/")){
            
             if (index>0){
                    if (this.listOperator.get(index-1).equals("+") || this.listOperator.get(index-1).equals("-")){
                     this.reckon(index);
                    }                
                    if( this.listOperator.get(index-1).equals("*") || this.listOperator.get(index-1).equals("/")){
                     this.perpareReckon( index-1);
                    }        
             }else{
             this.reckon(index);
             }            
            }
        }    
        
        /**
         * @param optPos 运算符位置
         * @return 运算结果
         * 该方法根据运算位置,分别取出运算值和运算符位置进行计算
         */
        private void reckon(int optPos){

         double temp=0 ;    
            if (this.listOperator.get(optPos).equals("*")){        
                temp = this.listNumbers.get(optPos).doubleValue() * this.listNumbers.get(optPos+1).doubleValue();
                System.out.println(this.listNumbers.get(optPos).doubleValue()+"*"+ this.listNumbers.get(optPos+1).doubleValue() + "="+temp);
                updateList(optPos , Double.valueOf(temp)) ;
                this.highOperateNum--; 
            }else if (this.listOperator.get(optPos).equals("/")){
                temp = this.listNumbers.get(optPos).doubleValue() / this.listNumbers.get(optPos+1).doubleValue();
                System.out.println(this.listNumbers.get(optPos).doubleValue()+"/"+ this.listNumbers.get(optPos+1).doubleValue() + "="+temp);
                updateList(optPos , Double.valueOf(temp)) ;
                this.highOperateNum--;                                   
            }else if (this.listOperator.get(optPos).equals("+")){
                temp = this.listNumbers.get(optPos).doubleValue() + this.listNumbers.get(optPos+1).doubleValue();
                System.out.println(this.listNumbers.get(optPos).doubleValue()+"+"+ this.listNumbers.get(optPos+1).doubleValue() + "="+temp);
                updateList(optPos , Double.valueOf(temp)) ;                                  
            }else if (this.listOperator.get(optPos).equals("-")){
                temp = this.listNumbers.get(optPos).doubleValue() - this.listNumbers.get(optPos+1).doubleValue();
                System.out.println(this.listNumbers.get(optPos).doubleValue()+"-"+ this.listNumbers.get(optPos+1).doubleValue() + "="+temp);
                updateList(optPos , Double.valueOf(temp)) ;                       
            }else{
             System.out.println("ERROR!!!!");
            }
        }
        
        /**
         * @param index 要在list中删除的值的index,以及
         * @param value 要新添加的值
         * 该方法用来在进行一次计算后,更新list.
         */
        private void updateList(int index , Double value){
            this.listNumbers.remove(index+1);
            this.listNumbers.remove(index);
            this.listNumbers.add(index,value);
            this.listOperator.remove(index);      
        }  
        
        public void cls(){
         this.highOperateNum = 0 ;
         this.listNumbers.clear();
         this.listOperator.clear();
        }
    }
    /**
     * 这个类在Formula的基础上添加了处理括号的能力。该类会把每个带括号的式子进行分解,
     * 每个括号的内容作为一个Formula实例来计算结果,并将结果合并到上一级的括号内。 * 
     */
    public class FormulaS {

    FormulaS(){}

    /**
     * @param str
     * @return 
     * 该类用来验证字符串格式。当前没有验证。直接返回true
     */
    private boolean validate(String str){return true;}

        public double getValue(String strOri){ 
        
         if (!this.validate(strOri)) return Double.NaN ;
        
            int prev = -1 ;
            int next = -1 ;        
            
            while ((prev=strOri.lastIndexOf('(')) != -1){
            
             StringBuffer sb = new StringBuffer();        
             sb.append(strOri.substring(0, prev));
             Formula f = new Formula(strOri.substring(prev+1, (next=strOri.indexOf(')'))));
             sb.append(f.getValue());
             sb.append(strOri.substring(next+1));
             f.cls();
             System.out.println("完成一个括号内部的计算");
             strOri = sb.toString() ;
            }
            
    return new Formula(strOri).getValue();
        }
        
        public static void main(String[] args) {          String str = "3+3-3*3/3*(2+2-2*2/2*(4+4-4*4/4)+5+5)+10+20-10" ;
         //第一次计算后的结果"3+3-3*3/3*(2+2-2*2/2*4+5+5)+10+20-10"
         //第二次计算后的结果"3+3-3*3/3*6+10+20-10"
        
         FormulaS fs = new FormulaS();    
         System.out.println("最后的运算结果为:"+fs.getValue(str));    
    }
    }