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

148 篇文章 1 订阅
59 篇文章 3 订阅

 /*
 * FormulaCalculator.java
 *
 * Created on 2007年9月18日, 上午11:40
 * @title 转化字符串表达式为数学公式并算出结果
 * @description 转化字符串表达式为数学公式并算出结果
 * 注意:为了区分负号,这边使用#代替减号
 * 使用方法:
 * 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;
    }

}

 

//:表达式解析-两栈算法.txt
//:Arithmetic.java

package   citi;
import   java.util.Iterator;
import   java.util.Stack;
import   java.util.ArrayList;

public   class   Arithmetic{
    //定义操作符,为简单起见,只涉及四则运算,可相应扩充之
    static   String   Operators= "+-*/()# ";
    //定义操作符的比较优先级,
    //其中1表示前面的操作符优于后面的操作符
    //       -1表示前面的操作符低于后面的操作符    
    //         0表示前面的操作符等于后面的操作符
    //         2表示前面的操作符不可能与后面的操作符相比较,如果碰到,则表达式有错    
    //PrecedeList[0][]表示+和+-*/()#这七个操作符相比较的优先级
    //PrecedeList[1][]表示-和+-*/()#这七个操作符相比较的优先级
    //以此类推
    static   byte   PrecedeList[][]={
                                                                {   1,   1,-1,-1,-1,   1,   1},
                                                                {   1,   1,-1,-1,-1,   1,   1},
                                                                {   1,   1,   1,   1,-1,   1,   1},
                                                                {   1,   1,   1,   1,-1,   1,   1},
                                                                {-1,-1,-1,-1,-1,   0,   2},
                                                                {   1,   1,   1,   1,   2,   1,   1},
                                                                {-1,-1,-1,-1,-1,   2,   0}};
    //定义数据中可能出现的数字和小数点,可以扩展
    static   String   Numbers= "0123456789. ";
    private   Stack   Operator,Operand;
    private   ArrayList   Expression;
   
    public   Arithmetic(String   inputStr){
    Operator=new   Stack();
    Operator.push( "# ");
    Operand=new   Stack();
    Expression=new   ArrayList();
    Parse(inputStr);
    }
    //解析输入的表达式,将操作符和数据分开
    //如输入表达式2+3*(32-2)则解析成2   +   3   *   (   32   -   2   )这九个字符串
    private   void   Parse(String   instr){
    String   single;    
    int   temp;
    String   tempstr= "# ";
    for(int   i=0;i <instr.length();i++){    
    single=instr.substring(i,i+1);
    //排除非操作符、数字的非法输入,如2+3m
    //Operators.indexOf(single)==6排除#
    if(Numbers.indexOf(single) <0   &&   (Operators.indexOf(single) <0   ||   Operators.indexOf(single)==6)){
    System.out.println( "Input   have   wrong   char: "+single);
    Expression.clear();
    return;
    }
    //获得前一个输入字符
    temp=Expression.size()-1;
    if(temp> -1){
    tempstr=(String)Expression.get(temp);
    }
    //排除连续两个操作符的情况,如3**2
    if(Operators.indexOf(single)> -1   &&   temp> -1   &&   Operators.indexOf(tempstr)> -1){
    System.out.println( "Input   have   wrong   format,two   Operators   are   conjoint ");
    Expression.clear();
    return;
    }    
    //如果当前字符是数字(包括.)而且前一字符也是数字,则将当前字符加到前一字符后面
    //其他情况均新添加一个元素
    if(Operators.indexOf(single) <0   &&   temp> -1   &&   Operators.indexOf(tempstr) <0){
    Expression.set(temp,tempstr+single);
    }    
    else{
        Expression.add(single);//其他情况均新添加一个元素
    }
    }    
    //为了算法处理方便起见,添加特殊字符#
    Expression.add( "# ");    
    }
   
    //比较两个操作符的优先级
    private   byte   Precede(String   firstOperator,String   secondOperator){
    return   PrecedeList[Operators.indexOf(firstOperator)][Operators.indexOf(secondOperator)];
    }    
   
    //对两个数据字符串进行运算
    private   double   Operate(String   firstOperand,String   Operator,String   secondOperand){
    if(Operator.equals( "+ ")){
    return   (Double.parseDouble(firstOperand)+Double.parseDouble(secondOperand));
    }
    else   if(Operator.equals( "- ")){
    return   (Double.parseDouble(firstOperand)-Double.parseDouble(secondOperand));
    }
    else   if(Operator.equals( "* ")){
    return   (Double.parseDouble(firstOperand)*Double.parseDouble(secondOperand));
    }
    else   if(Operator.equals( "/ ")){
    return   (Double.parseDouble(firstOperand)/Double.parseDouble(secondOperand));
    }
    else{
        System.out.println( "Operator   is   wrong!Can   throw   a   Exception ");
        return   0;
        }
    }
    //采用两个栈对接解析后的表达式进行运算
    public   double   Compute(){
    if(Expression.isEmpty()){
    System.out.println( "Expresion   is   empty ");
    return   0;
    }
    Iterator   it   =   Expression.iterator();
    String   single;
    String   firstOperand,secondOperand;
       
    single=(String)it.next();
    while(!(single.equals( "# ")   &&   Operator.peek().equals( "# "))){
    if(Operators.indexOf(single) <0){
    Operand.push(single);single=(String)it.next();
    }
    else{
        switch(Precede((String)Operator.peek(),single)){
        case   -1:Operator.push(single);single=(String)it.next();break;
        case   0:   Operator.pop();single=(String)it.next();break;
        case   1:  
                        secondOperand=(String)Operand.pop();
                        firstOperand=(String)Operand.pop();
                        Operand.push(String.valueOf(Operate(firstOperand,(String)Operator.pop(),secondOperand)));break;
        case   2:   System.out.println( "Expression   is   wrong!Can   throw   a   Exception ");break;
        }
        }
    }    
        return   Double.parseDouble((String)Operand.pop());
    }
   
    public   static   void   main(String[]   args){
    long   t1   =   System.currentTimeMillis();        
       
    Arithmetic   t=new   Arithmetic(args[0]);
    System.out.println(t.Compute());    
   
    long   t2   =   System.currentTimeMillis();
        System.out.println( "Time   needed:   "   +   (t2   -   t1));
    }
}

 

 

C# code
   
   
using System; using System.Text; namespace Lentro.Edu.Ch02 { public class Expression { private StackSimple<int> theStack; public StringBuilder suffix = new StringBuilder(); /** * 检查该字符是否为括号 */ private bool isParen(char c) { if (c == '{' || c == '[' || c == '(' || c == ')' || c == ']' || c == '}') return true; else return false; } /** * 检查是否为左括号 */ private bool isLeftParen(char c) { if (c == '{' || c == '[' || c == '(') return true; else return false; } /** * 判断指定的操作符是否为 '+' 或者 '-' */ private bool isAddOrSub(int oper) { return oper == '+' || oper == '-'; } /** * 检查是否为数字 */ private bool isNumber(int ch) { return ch >= 48 && ch <= 57; } /** * 检查表达式是否合法 */ private bool checkExp(String exp) { char[] ch = exp.ToCharArray(); StackSimple<int> theStackXInt = new StackSimple<int>(exp.Length / 2); /** * 遍历表达式,只处理括号部分 */ for (int i = 0; i < ch.Length; i++) { char c = ch[i]; if (isParen(c)) { /** * 左括号进栈 */ if (isLeftParen(c)) { theStackXInt.Push(c); } else { if (theStackXInt.IsEmpty()) { return false; } int left = theStackXInt.Pop(); switch (c) { case '}': if (left != '{') return false; break; case ']': if (left != '[') return false; break; case ')': if (left != '(') return false; break; } } } } if (theStackXInt.IsEmpty()) { return true; } else { return false; } } /** * 根据当前操作符处理之前在栈中的操作符,当前操作符暂不处理,放入栈中 */ private void processOper(char oper) { while (!theStack.IsEmpty()) { int currTop = theStack.Pop(); /** * 如果是左括号,则不予处理,将括号返回进栈 * * 若得到的操作符,则进一步判断 */ if (currTop == '(') { theStack.Push(currTop); break; } else { if (this.isAddOrSub(currTop)) { if (this.isAddOrSub(oper)) { this.suffix.Append((char)currTop); } else { this.theStack.Push(currTop); break; } } else { this.suffix.Append((char)currTop); break; } } } /** * 当前操作符进栈 */ theStack.Push(oper); } /** * 处理括弧. * * 如果为左括弧,直接进栈; * * 否则为右括弧,现将这一对括号中的操作符优先处理完 */ private void processParen(char paren) { if (this.isLeftParen(paren)) { this.theStack.Push(paren); } else { while (!theStack.IsEmpty()) { int chx = theStack.Pop(); if (chx == '(') break; else suffix.Append((char)chx); } } } /** * 将正确的中缀表达式转为后缀表达式 */ private void doTrans(String exp) { theStack = new StackSimple<int>(exp.Length); if (this.checkExp(exp)) { char[] ch = exp.ToCharArray(); for (int i = 0; i < ch.Length; i++) { char c = ch[i]; switch (c) { case '+': case '-': case '*': case '/': this.processOper(c); break; case '(': case ')': this.processParen(c); break; default: this.suffix.Append(c); break; } } while (!this.theStack.IsEmpty()) { this.suffix.Append((char)this.theStack.Pop()); } } } /** * 计算表达式 */ public int clac(String exp) { this.doTrans(exp); String suff = this.suffix.ToString(); StackSimple<int> stack = new StackSimple<int>(suff.Length); if (suff == null || suff.Length == 0) { } else { char[] ch = suff.ToCharArray(); for (int i = 0; i < ch.Length; i++) { char c = ch[i]; if (this.isNumber(c)) { stack.Push(c - 48); } else { int operand2 = stack.Pop(); int operand1 = stack.Pop(); switch (c) { case '+': stack.Push(operand1 + operand2); break; case '-': stack.Push(operand1 - operand2); break; case '*': stack.Push(operand1 * operand2); break; case '/': stack.Push(operand1 / operand2); break; } } } } return stack.Peep(); } } }



其中StackSimple是自己写的一个简单的栈实现

C# code

   
   
using System; namespace Lentro.Edu.Ch02 { /// <summary> /// 用于演示栈(LIFO)的内部实现机制 /// /// xfeng/2010-05-07 /// </summary> public class StackSimple<T> { //栈默认的初始容量大小 private const int DEFAULT_SIZE = 10; private T[] array; private int index; /// <summary> /// 初始化 Stack 类的新实例,该实例为空并且具有默认初始容量。 /// </summary> public StackSimple() : this(DEFAULT_SIZE) { } /// <summary> /// 初始化 Stack 类的新实例,该实例为空并且具有指定的初始容量。 /// </summary> /// <param name="size"></param> public StackSimple(int size) { index = -1; this.array = new T[size]; } private int _count; /// <summary> /// 获取 Stack 中包含的元素数。 /// </summary> public int Count { get { return _count; } } /// <summary> /// 清空栈 /// </summary> public void Clear() { for (int i = 0; i < array.Length; i++) { array[i] = default(T); this.index = -1; this._count = 0; } } public Boolean IsEmpty() { return this._count == 0; } /// <summary> /// 返回位于 Stack 顶部的对象但不将其移除。 /// </summary> /// <returns>位于 Stack 顶部的 Object。</returns> public T Peep() { return this.index < 0 ? default(T) : this.array[this.index]; } /// <summary> /// 移除并返回位于 Stack 顶部的对象。 /// </summary> /// <returns>从 Stack 的顶部移除的 Object。 </returns> public T Pop() { T obj = this.index < 0 ? default(T) : this.array[this.index]; if (null != obj) { this.index--; this._count--; //this.array[this.index] = default(T); } return obj; } /// <summary> /// 将对象插入 Stack 的顶部。 /// </summary> public void Push(T obj) { if (null != obj) { if (this.index >= this.array.Length - 1) { T[] temp = new T[this.array.Length * 2]; int count = 0; foreach (T item in array) { temp[count++] = item; } this.array = temp; } array[++index] = obj; this._count++; } } } }



这是那个栈Demo

C#的动态编译,并返回结果

C# code  

        private void btn_Compute_Click(object sender, EventArgs e)
        {
            // 声明要计算C#代码,要求必须完整的C#代码
            string strCode = @"
                    using System;
                    namespace ParseEx
                    {
                        public class ParseExC
                        {
                            public static double GetValue()  //GetValue(int x) //可以带参数
                            {
                                return 1+5*8-(Math.Sin(12)*2.5);
                            }
                        }
                    }";

            Stopwatch sw = new Stopwatch();
            sw.Start();
            string strCode = @"
                    using System;
                    namespace ParseEx
                    {
                        public class ParseExC
                        {
                            public static double GetValue()
                            {"
            + "return " + this.textBox_Text.Text.Trim() + ";" +
                            @"}
                        }
                    }";
           
            CodeDomProvider comp = new CSharpCodeProvider();
            CompilerParameters cp = new CompilerParameters();

            StringBuilder codeBuilder = new StringBuilder();
            codeBuilder.AppendLine(strCode);

            cp.ReferencedAssemblies.Add("System.dll");
            cp.GenerateExecutable = false;
            cp.GenerateInMemory = true;

            CompilerResults cr = comp.CompileAssemblyFromSource(cp, codeBuilder.ToString());
            if (cr.Errors.HasErrors)
            {
                MessageBox.Show("Error!");
            }
            else
            {
                Assembly a = cr.CompiledAssembly;
                if (a != null)
                {
                    Type t = a.GetType("ParseEx.ParseExC");
                    if (t != null)
                    {
                        // 因为是静态调用,不需要创建实例了
                        // object mode = a.CreateInstance("Mode");
                        MethodInfo mi = t.GetMethod("GetValue", BindingFlags.Static | BindingFlags.Public);
                        if (mi != null)
                        {
                            double d = (double)mi.Invoke(null, null);

//double d = (double)mi.Invoke(null, new object[] { 1 }) });  //可以带参数

                            sw.Stop();

                            this.label_Result.Text = "Result = " + d.ToString() + "; Time = " + sw.Elapsed.ToString();
                            //MessageBox.Show("Result = " + d.ToString());
                        }
                    }
                }
            }
        }
    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值