就是Java获取这么一个表达式后,如何进行解析并得出计算结果?
多谢!

解决方案 »

  1.   

    建议参考编译原理方面的资料。对于四则运算可以参考下面的代码,当然也可以扩展到其他运算:
    //:表达式解析-两栈算法.txt
    //:Arithmetic.javapackage 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));
      }
    }运行:
    F:\java>javac Arithmetic.java -d .F:\java>java citi.Arithmetic 3*(34+4*4)
    150.0
    Time needed: 10
      

  2.   

    虽然我还没有看懂,不过我想这个算法好像只能解决简单的运算问题,不过还是要感谢tangshancheng!
    各位大虾,有没有更好的?
      

  3.   

    估计不会太难,在编译原理的书有很多例子
    可以这样考虑使用递归求解.
    先做一个简单的if求解过程.
    再设定一个递归结束条件.
    在清华的数据结构(c++)上有现成的例子.
      

  4.   

    我觉得没必要写个运算器吧,可不可以这样,Excel的表达式让excel去解释,java只取其结果,excel的运算必然会写到一个格中去吧,就在那儿取结果不更省事吗,不知楼主的意思是不是这样...
      

  5.   

    Jakarta POI 可以很方便的解决
      

  6.   

    我花了些时间终于完成了这么一个烂东西,解决方法可能不是很优化,不过也发布出来让大家参考参考,如果各位大虾有更好的解决方案,还请mail给我:[email protected] java.util.*;
    public class Calculator
    { public Calculator(){ }
    /*
    public Calculator(String data)
    {
    bits = data.toCharArray();
    }
    */
    /**
     * 计算
     * @return double类型的计算结果
     * @throws ArithmeticException 计算出现错误
     * @throws NumberFormatException 数据格式错误
     */
    public double evaluate(String data)
    throws ArithmeticException, NumberFormatException
    {
    if(data.toLowerCase().indexOf("if")>=0)
    data = evalIfFunction(data);
    bits = data.toCharArray();
    pos = 0;
    double ret = evalPlusMinus(); if (pos != bits.length) {
    throw new NumberFormatException("Garbage at end of equation");
    } return ret;
    }
    public double evaluate(double x, String data)
    throws ArithmeticException, NumberFormatException
    {
    this.x = x;
    return evaluate(data);
    } private void skipWS()
    {
    while ((pos < bits.length) && Character.isWhitespace(bits[pos])) {
    pos++;
    }
    } private double evalReal() throws NumberFormatException
    {
    skipWS();
    int save = pos; while ((pos < bits.length) && Character.isDigit(bits[pos])) {
    pos++;
    } if ((pos == save) && (bits[pos] != '.')) {
    throw new NumberFormatException("pos != save");
    } if ((pos < bits.length) && bits[pos] == '.') {
    int saved = ++pos; while ((pos < bits.length) && Character.isDigit(bits[pos])) {
    pos++;
    } if (pos == saved) {
    throw new NumberFormatException("Invalid numeric literal");
    }
    } return Double.valueOf(new String(bits, save, pos-save)).doubleValue();
    } private double evalSymbol()
    throws ArithmeticException, NumberFormatException
    {
    double lhs = 0.0;
    int skip = pos; while ((skip < bits.length)&& Character.isLetterOrDigit(bits[skip])) {
    skip++;
    } if (skip > pos) {
    String symbol = new String(bits, pos, skip-pos); if (symbol.equals("pi")) {
    lhs = Math.PI;
    } else if (symbol.equals("e")) {
    lhs = Math.E;
    } else if (symbol.equals("x")) {
    lhs = x;
    } else {
    throw new NumberFormatException("Unknown symbol: " + symbol);
    }
    pos = skip;
    } return lhs;
    }
    private double evalFunction()
    throws ArithmeticException, NumberFormatException,
       SymbolNotFoundException
    {
    double lhs = 0.0;
    int skip = pos; while ((skip < bits.length)&& Character.isLetterOrDigit(bits[skip])) {
    skip++;
    } if (skip > pos) {
    String symbol = new String(bits, pos, skip-pos);
    int saved = pos; pos = skip; if (symbol.equals("sin")) {
    lhs = Math.sin(evalTerm());
    } else if (symbol.equals("cos")) {
    lhs = Math.cos(evalTerm());
    } else if (symbol.equals("tan")) {
    lhs = Math.tan(evalTerm());
    } else if (symbol.equals("asin")) {
    lhs = Math.asin(evalTerm());
    } else if (symbol.equals("acos")) {
    lhs = Math.acos(evalTerm());
    } else if (symbol.equals("atan")) {
    lhs = Math.atan(evalTerm());
    } else if (symbol.equals("ln")) {
    lhs = Math.log(evalTerm());
    } else if (symbol.equals("deg")) {
    lhs = Math.toDegrees(evalTerm());
    } else if (symbol.equals("rad")) {
    lhs = Math.toRadians(evalTerm());
    } else{
    pos = saved;
    throw new SymbolNotFoundException();
    } if (Double.isNaN(lhs)) {
    throw new ArithmeticException(symbol + ": Invalid Domain");
    }
    } return lhs;
    } private double evalTerm()
    throws ArithmeticException, NumberFormatException
    {
    double lhs = 0.0;
    skipWS(); switch (bits[pos]) {
    case '(':
    pos++;
    lhs = evalPlusMinus();
    skipWS();
    if ((pos < bits.length) && (bits[pos] == ')')) {
    pos++;
    } else {
    throw new NumberFormatException("Missing ')' in expression");
    }
    break;
    case '[':
    pos++;
    lhs = evalPlusMinus();
    skipWS();
    if ((pos < bits.length) && (bits[pos] == ']')) {
    pos++;
    } else {
    throw new NumberFormatException("Missing ']' in expression");
    }
    break; default:
    if (Character.isDigit(bits[pos]) || (bits[pos] == '.')) {
    lhs = evalReal();
    } else if (Character.isLetter(bits[pos])) {
    try {
    lhs = evalFunction();
    } catch (SymbolNotFoundException sym) {
    lhs = evalSymbol();
    }
    } else {
    throw new NumberFormatException("Expecting Term");
    }
    break;
    } return lhs;
    }
    private double evalUnary()
    throws ArithmeticException, NumberFormatException
    {
    double lhs = 0.0;
    skipWS(); if (pos >= bits.length) {
    throw new NumberFormatException("Premature expression end");
    } switch (bits[pos]) {
    case '-':
    pos++;
    lhs = -evalUnary();
    break;
    case '+':
    pos++;
    lhs = evalUnary();
    break;
    default:
    lhs = evalTerm();
    break;
    } return lhs;
    } private double evalExponent()
    throws ArithmeticException, NumberFormatException
    {
    double lhs = evalUnary();
    boolean need_more = true;
    skipWS(); while ((pos < bits.length) && need_more) {
    switch (bits[pos]) {
    case '^':
    pos++;
    lhs = Math.pow(lhs, evalUnary());
    break;
    case '!':
    int lhs_int = (int)lhs;
    pos++; if (lhs < 0 || lhs_int != lhs) {
    throw new ArithmeticException("Invalid domain");
    } lhs = 1.0;
    for(int i = 2; i <= lhs_int; i++) {
    lhs *= i;
    }
    break;
    case '%':
    pos++;
    lhs /= 100;
    break;
    default:
    need_more = false;
    break;
    }
    } return lhs;
    } private double evalMultDivide()
    throws ArithmeticException, NumberFormatException
    {
    double lhs = evalExponent();
    boolean need_more = true;
    skipWS(); while ((pos < bits.length) && need_more) {
    switch (bits[pos]) {
    case '*':
    pos++;
    lhs *= evalExponent();
    break;
    case '/':
    pos++;
    lhs /= evalExponent();
    break;
    default:
    need_more = false;
    break;
    }
    } return lhs;
    } private double evalPlusMinus()
    throws ArithmeticException, NumberFormatException
    {
    double lhs = evalMultDivide();
    boolean need_more = true;
    skipWS(); while ((pos < bits.length) && need_more) {
    switch (bits[pos]) {
    case '-':
    pos++;
    lhs -= evalMultDivide();
    break;
    case '+':
    pos++;
    lhs += evalMultDivide();
    break;
    default:
    need_more = false;
    break;
    }
    } return lhs;
    } private char bits[];
    private int pos = 0;
    private double x = 0.0; private int ifPos = 0;#太长了...,再来一贴...
      

  7.   

    #续上贴....
    private String evalIfFunction(String express) throws ArithmeticException, NumberFormatException{
    int lastIfPos = express.lastIndexOf("if");
    if(lastIfPos<0) return express; ifPos = lastIfPos;
    String beforeIf = express.substring(0,lastIfPos);
    String afterIf = express.substring(ifPos);
    bits = afterIf.toCharArray();
    double ifValue = evalLastIf(); String nonIfString = beforeIf + String.valueOf(ifValue) + afterIf.substring(ifPos);
    express = evalIfFunction(nonIfString);
    return express; }
    private double evalLastIf() throws ArithmeticException, NumberFormatException{
    double x = 0.0;
    skipWS();
    int skip = 0;
    String compareExpress=null;
    String trueTerm=null;
    String falseTerm=null; while((skip<bits.length) && bits[skip]!=','){
    skip++;
    }
    if(skip>0){
    compareExpress = new String(bits, 3, skip-3);
    }
    //get the true expression
    skip++;
    ifPos = skip;
    while( (skip<bits.length)&& bits[skip]!=','){
    skip++;
    }
    if(skip>pos){
    trueTerm = new String(bits, ifPos, skip-ifPos);
    ifPos = skip;
    }
    //get the false expression
    skip++;
    ifPos = skip;
    int leftBracket = 0;
    int rightBracket = 0;
    while((skip<bits.length) && bits[skip]!=')'){
    if(bits[skip]=='('){
    leftBracket ++;
    }
    skip++;
    }
    while(rightBracket<leftBracket+1){
    if(bits[skip]==')'){
    rightBracket++;
    }
    skip++;
    }
    if(skip>ifPos){
    falseTerm = new String(bits, ifPos, skip-ifPos-1);
    ifPos = skip;
    } boolean compare = evalCompare(compareExpress);
    if(compare){
    x = this.evaluate(trueTerm);
    }else{
    x = this.evaluate(falseTerm);
    }
    return x;
    }
    private boolean evalCompare(String express) throws ArithmeticException, NumberFormatException {
    boolean isTrue = false;
    char[] ifBits = express.toCharArray();
    String partA = null;
    String partB = null;
    String compareType = null; int i = 0;
    int skip = 0;
    while(skip<ifBits.length && !isCompareFlag(ifBits[skip])){
    skip++;
    }
    partA = new String(ifBits, i, skip);
    i = skip; if(ifBits[skip+1]!='='){
    compareType = new String(ifBits,skip,1);
    partB = new String(ifBits,++skip,ifBits.length - skip);
    }else{
    compareType = new String(ifBits, skip, 2);
    partB = new String(ifBits, skip+2, ifBits.length - skip-2);
    }
    double a = this.evaluate(partA);
    double b = this.evaluate(partB);
    if(compareType.length()==1){
    char[] compareChar = compareType.toCharArray();
    switch(compareChar[0]){
    case '>':
    return (a>b);
    case '<':
    return (a<b);
    case '=':
    return (a==b);
    default:
    return false;
    }
    }else{
    if(compareType.equals(">=")){
    return (a>b || a==b);
    }else if(compareType.equals("<=")){
    return (a<b || a==b);
    }
    } return isTrue;
    }
    private boolean isCompareFlag(char c){
    boolean isCompare = false;
    switch(c){
    case '>':
    return true;
    case '<':
    return true;
    case '=':
    return true;
    }
    return false;
    }
    }