转化字符串表达式为数学公式并算出结果—实用类

来源:互联网 发布:韩侂胄。知乎 编辑:程序博客网 时间:2024/04/29 03:33

/*   
  * FormulaCalculator calculator=new FormulaCalculator();
  * calculator.getResult("10.23#20.67*(5.12+7.82)/2",2);
  * v1.0.0 created by chenfc
  *
   */ 
 
 package  org.jceun;
 
 import  java.math.BigDecimal;
 import  java.util.LinkedList;
 import  java.util.ArrayList;
 import  java.util.regex.Matcher;
 import  java.util.regex.Pattern;
 
  public   class  FormulaCalculator  ... {
      private    boolean  isRightFormat  =   true ;
      public   String DIVISOR_EQUALS_ZERO = " 0.0 " ; // 除数为零时的返回值 
       /** */ /** 
      * 为了区分负号,这边使用#代替减号
      *  @param  formula 字符串表达式
      *  @return  返回公式计算结果
       */ 
       public    double  getResult(String formula) ... {
          double  returnValue  =   0 ;
           try ... {
             returnValue  =  doAnalysis(formula);
          } catch (NumberFormatException nfe) ... {
             System.out.println( " 公式格式有误,请检查: "   +  formula);
          } catch (Exception e) ... {
             e.printStackTrace();
         } 
           if ( ! isRightFormat) ... {
             System.out.println( " 公式格式有误,请检查: "   +  formula);
         } 
          return  returnValue;
     } 
       /** */ /** 
      * 采用BigDecimal.ROUND_HALF_UP方式返回指定精度的运算结果
      *  @param  formula 公式
      *  @param  decimalPlace 要保留的小数位数
      *  @return  返回公式计算结果
       */ 
       public   String getResult(String formula, int  decimalPlace) ... {
          return  getResult(formula,decimalPlace,BigDecimal.ROUND_HALF_UP);
     } 
       /** */ /** 
      * 返回指定精度及舍去尾数的策略的运算结果
      *  @param  formula 公式
      *  @param  decimalPlace 要保留的小数位数
      *  @param  roundMethod 舍去尾数的策略
      *          可取值有BigDecimal.ROUND_HALF_UP BigDecimal.ROUND_HALF_DOWN祥见BigDecimal
      *  @return  返回公式计算结果
       */ 
       public   String getResult(String formula, int  decimalPlace, int  roundMethod) ... {
          double  result = getResult(formula);
          if (result == Double.MAX_VALUE)
              return  DIVISOR_EQUALS_ZERO;
          else 
              return  numberAround(result,decimalPlace,roundMethod);
     } 
       private    double  doAnalysis(String formula) ... {
          double  returnValue  =   0 ;
         LinkedList < Integer >  stack  =   new  LinkedList < Integer > ();
         
          int  curPos  =   0 ;
         String beforePart  =   "" ;
         String afterPart  =   "" ;
         String calculator  =   "" ;
         isRightFormat  =   true ;
           while (isRightFormat && (formula.indexOf( ' ( ' )  >=   0 || formula.indexOf( ' ) ' )  >=   0 )) ... {
             curPos  =   0 ;
               for ( char  s : formula.toCharArray()) ... {
                   if (s  ==   ' ( ' ) ... {
                     stack.add(curPos);
                  } else   if (s  ==   ' ) ' ) ... {
                       if (stack.size()  >   0 ) ... {
                         beforePart  =  formula.substring( 0 , stack.getLast());
                         afterPart  =  formula.substring(curPos  +   1 );
                         calculator  =  formula.substring(stack.getLast()  +   1 , curPos);
                         formula  =  beforePart  +  doCalculation(calculator)  +  afterPart;
                         stack.clear();
                          break ;
                      } else ... {
                         System.out.println( " 有未关闭的右括号! " );
                         isRightFormat  =   false ;
                     } 
                 } 
                 curPos ++ ;
             } 
               if (stack.size()  >   0 ) ... {
                 System.out.println( " 有未关闭的左括号! " );
                  break ;
             } 
         } 
           if (isRightFormat) ... {
             returnValue  =  doCalculation(formula);
         } 
          return  returnValue;
     } 
       /** */ /** 
      * 为了区分负号,这边使用#代替减号
       */ 
       private    double  doCalculation(String formula)  ... {
         ArrayList < Double >  values  =   new  ArrayList < Double > ();
         ArrayList < String >  operators  =   new  ArrayList < String > ();
          int  curPos  =   0 ;
          int  prePos  =   0 ;
           for  ( char  s : formula.toCharArray())  ... {
               if  (s  ==   ' + '   ||  s  ==   ' # '   ||  s  ==   ' * '   ||  s  ==   ' / ' )  ... {
                 values.add(Double.parseDouble(formula.substring(prePos, curPos)
                 .trim()));
                 operators.add( ""   +  s);
                 prePos  =  curPos  +   1 ;
             } 
             curPos ++ ;
         } 
         values.add(Double.parseDouble(formula.substring(prePos).trim()));
          char  op;
           for  (curPos  =  operators.size()  -   1 ; curPos  >=   0 ; curPos -- )  ... {
             op  =  operators.get(curPos).charAt( 0 );
               switch  (op)  ... {
                  case   ' * ' :
                     values.add(curPos, values.get(curPos)  *  values.get(curPos  +   1 ));
                     values.remove(curPos  +   1 );
                     values.remove(curPos  +   1 );
                     operators.remove(curPos);
                      break ;
                  case   ' / ' :
                      if (values.get(curPos  +   1 ).doubleValue() == 0.0 ) // 除数为零时 
                         values.add(curPos,  new  Double(getDefaultValue()));
                      else 
                         values.add(curPos, values.get(curPos)  /  values.get(curPos  +   1 ));
                     values.remove(curPos  +   1 );
                     values.remove(curPos  +   1 );
                     operators.remove(curPos);
                      break ;
             } 
         } 
           for  (curPos  =  operators.size()  -   1 ; curPos  >=   0 ; curPos -- )  ... {
             op  =  operators.get(curPos).charAt( 0 );
               switch  (op)  ... {
                  case   ' + ' :
                     values.add(curPos, values.get(curPos)  +  values.get(curPos  +   1 ));
                     values.remove(curPos  +   1 );
                     values.remove(curPos  +   1 );
                     operators.remove(curPos);
                      break ;
                  case   ' # ' :
                     values.add(curPos, values.get(curPos)  -  values.get(curPos  +   1 ));
                     values.remove(curPos  +   1 );
                     values.remove(curPos  +   1 );
                     operators.remove(curPos);
                      break ;
             } 
         } 
          return  values.get( 0 ).doubleValue();
     } 
       /** */ /** 
      * 对数字进行四舍五入
      *  @param  dN 要四舍五入的数
      *  @param  decimalPlace 精度
      *  @param  roundMethod 舍去尾数的策略
      *          可取值有BigDecimal.ROUND_HALF_UP BigDecimal.ROUND_HALF_DOWN祥见BigDecimal
       */ 
       public   String numberAround( double  dN, int  decimalPlace,  int  roundMethod) ... {
         BigDecimal bd  =   new  BigDecimal(String.valueOf(dN));
         bd  =  bd.setScale(decimalPlace, roundMethod);
          return  String.valueOf(bd);
     } 
       /** */ /** 
      * 对给定的字符串进行模式匹配
      *  @param  str 要匹配的字符串
      *  @param  regix 模式
      *  @return  返回匹配结果,成功为true,否则为false
      * */ 
       public    boolean  check(String str,String regix) ... {
          boolean  result = false ;
         Pattern p = Pattern.compile(regix);
         Matcher m  = p.matcher(str);
         result = m.matches();
          return  result;
     } 
 }


原创粉丝点击