数字表达式解析器

昨天匆忙写完的,估计还有bug,这里说明一点,对于parseInt没有直接使用parseDouble是不是有点重复,我不希望用浮点计算来牺牲性能!有空我再补充说明。

package treeroot.util.parser;


class Operation {
  private int priority;
  private Operation(int priority) {
    this.priority = priority;
  }

  public int getPriority() {
    return this.priority;
  }

  public static Operation PLUS = new Operation(1);
  public static Operation MINUS = new Operation(1);
  public static Operation MULTIPLY = new Operation(2);
  public static Operation DIVIDE = new Operation(2);
  public static Operation MOD = new Operation(2);
}

package treeroot.util.parser;


class Bracket {
 private Bracket(){}
 public static Bracket LEFT = new Bracket();
   public static Bracket RIGHT = new Bracket();
}


package treeroot.util.parser;


import java.util.*;
class Stack {
 private List data=new ArrayList();
 private int size=0;
 public boolean empty(){
  return size==0;
 }
 public void push(Object o){
  data.add(o);
  size++;
 }
 public Object pop(){
  if(size>0){
   return data.remove(--size);
  }
  return null;
 }
 public Object peek(){
  if(size>0) return data.get(size-1);
  return null;
 }
 
}

package treeroot.util.parser;


class Compute {

 static int compute(int n1, int n2, Operation op) {

    if (op == Operation.PLUS) {
      return n1 + n2;
    }
    else if (op == Operation.MINUS) {
      return n1 - n2;
    }
    else if (op == Operation.DIVIDE) {
      return  n1 / n2;
    }
    else if (op == Operation.MULTIPLY) {
      return n1 * n2;
    }
    else if (op == Operation.MOD) {
      return  n1 % n2;
    }
    else {
      throw new UnsupportedOperationException();
    }
  }
  static double compute(double n1, double n2, Operation op) {
    if (op == Operation.PLUS) {
      return n1 + n2;
    }
    else if (op == Operation.MINUS) {
      return n1 - n2;
    }
    else if (op == Operation.DIVIDE) {
      return  n1 / n2;
    }
    else if (op == Operation.MULTIPLY) {
      return n1 * n2;
    }
    else if (op == Operation.MOD) {
      return  n1 % n2;
    }
    else {
      throw new UnsupportedOperationException();
    }
  }
}

//下面为核心代码


package treeroot.util.parser;


/**
 * support +,-,*,/,%,(,),+-(sign),dot(.) for double
 * int double
 */
import java.util.List;
import java.util.ArrayList;
import java.text.ParseException;

public class ExpressionParser {
  private ExpressionParser(){}
 
  private static char[] validCharsForInt={'0','1','2','3','4','5','6','7','8','9','+','-',
   '*','/','%','(',')'};
  private static char[] validCharsForDouble={'0','1','2','3','4','5','6','7','8','9','+','-',
   '*','/','%','(',')','.'};
 
  //check the valid char of the expression for the int compute
  private static boolean validCharForInt(char c){
    for(int i=0;i<validCharsForInt.length;i++){
     if(validCharsForInt[i]==c) return true;
    }
    return false;
  }
  //check the valid char of the expression for the double compute
  private static boolean validCharForDouble(char c){
   for(int i=0;i<validCharsForDouble.length;i++){
    if(validCharsForDouble[i]==c) return true;
   }
   return false;
  }
  private static void checkValidCharForInt(char c,int index) throws ParseException{
   if(!validCharForInt(c))
      throw new ParseException("invlaid char at index "+index+" of the Expression!",index);  
       
  }
  private static void checkValidCharForDouble(char c,int index) throws ParseException{
   if(!validCharForDouble(c)){
    throw new ParseException("invalid char at index "+index+" of the Expression!",index);
   }
  }
  private final static int NULL=0;
  //0..9
  private final static int NUMBER=0x1; 
  //+,-,*,/,%
  private final static int OPERATION=0x10;
  //(
  private final static int LEFT_BRACKET=0x100;
  //)
  private final static int RIGHT_BRACKET=0x1000;
  //+-
  private final static int SIGN=0x10000;
  //. for the double
  private final static int DOT=0x100000;
 
 
 
  private static int NULL_AFTER=NUMBER+LEFT_BRACKET+SIGN;
  private static int NUMBER_AFTER=NUMBER+OPERATION+RIGHT_BRACKET+DOT;
  private static int OPERATION_AFTER=NUMBER+LEFT_BRACKET;
  private static int LEFT_BRACKET_AFTER=NUMBER+LEFT_BRACKET+SIGN;
  private static int RIGHT_BRACKET_AFTER=OPERATION+RIGHT_BRACKET;
  private static int SIGN_AFTER=NUMBER+LEFT_BRACKET;
  private static int DOT_AFTER=NUMBER;
 
  //for the convinent
  private static int[] TYPE={NULL,NUMBER,OPERATION,LEFT_BRACKET,RIGHT_BRACKET,
   SIGN,DOT};
  private static int[] EXPECT_AFTER={NULL_AFTER,NUMBER_AFTER,OPERATION_AFTER,
   LEFT_BRACKET_AFTER,RIGHT_BRACKET_AFTER,SIGN_AFTER,DOT_AFTER};
 
 
  private static boolean isEndType(int type){
    return (type==NUMBER)||(type==RIGHT_BRACKET);
  }
  private static int getValidAfter(int type){
    for(int i=0;i<TYPE.length;i++){
     if(TYPE[i]==type) return EXPECT_AFTER[i];
    }
    throw new IllegalArgumentException();
  }
 
  private static String expectString(int type){
    StringBuffer sb=new StringBuffer();
    int expect=getValidAfter(type);
    if((expect&NUMBER)>0){
     sb.append("number[0-9],");
    }
    if((expect&OPERATION)>0){
     sb.append("operation[+-*/%],");
    }
    if((expect&LEFT_BRACKET)>0){
     sb.append("brack[(],");
    }
    if((expect&RIGHT_BRACKET)>0){
     sb.append("brack[)],");
    }
    if((expect&SIGN)>0){
     sb.append("sign[+-],");
    }
    if((expect&DOT)>0){
     sb.append("dot[.],");
    }
    sb.setLength(sb.length()-1);
    return sb.toString();
  }
 
  private static boolean checkExpect(int type,int next){
   int expect=getValidAfter(type);
   return (next&expect)>0;
  } 
 
  private static void checkExpect(int type,int next,int index) throws ParseException{
   if(!checkExpect(type,next)){
    throw new ParseException(expectString(type)+" expected at index "+index,index);
   } 
  }
 
  public static double parseDouble(String expression) throws ParseException{
    if ((expression == null) | (expression=expression.trim()).equals("")) {
       throw new NullPointerException("expression can't be null or blank!");
     }
  Stack stack=new Stack();
  int curType=NULL;
  boolean isNegative=false;
  int leftBrackets=0;
     int dot=0;
     StringBuffer sb=new StringBuffer();
    
     for (int i = 0; i < expression.length(); i++) {
       Object push=null;
       char c = expression.charAt(i);
      //ignore blank
      while(c==' '){
       i++;
       c=expression.charAt(i);
      }
      //check valid char
      checkValidCharForDouble(c,i);
       
       switch (c) {
        case '+':
        case '-':
         checkExpect(curType,OPERATION+SIGN,i);
         //the operation must after number or )
         if((curType==NUMBER)||(curType==RIGHT_BRACKET)){
          curType=OPERATION;
          if(c=='+') push=Operation.PLUS;
          else push=Operation.MINUS;
         }
         //sign must after ( or at the begining.
         else{
          curType=SIGN;
          if(c=='-') isNegative=true;
          else isNegative=false;
         }
            break;
        case '*':
        case '/':
        case '%':
          checkExpect(curType,OPERATION,i);
          if(c=='*') push=Operation.MULTIPLY;
          else if(c=='/') push=Operation.DIVIDE;
          else push=Operation.MOD;
                    
          curType=OPERATION;
           break;
        case '(':
         checkExpect(curType,LEFT_BRACKET,i);
         push=Bracket.LEFT;
         
         curType=LEFT_BRACKET;
         leftBrackets++;
         break;
        case ')':
         checkExpect(curType,RIGHT_BRACKET,i);
         push=Bracket.RIGHT;
         
         curType=RIGHT_BRACKET;
         leftBrackets--;
         if(leftBrackets<0) throw new IllegalArgumentException("unmatched right bracket at inidex "+i);
         break;
        case '.':
         checkExpect(curType,DOT,i);
         dot++;
         if(dot>1) throw new IllegalArgumentException("redundant dot at index "+i);
         sb.append(c);
         curType=DOT;
         break;
        default:
            //must be number
            checkExpect(curType,NUMBER,i);
            sb.append(c);
      curType=NUMBER;    
        
      }
     
     
      //if it is a negative sign then push number -1 and *
      if((curType==SIGN)&&(isNegative)){
       stack.push(new Double(-1));
       stack.push(Operation.MULTIPLY);
      }
     
     
      // read a number
      if((curType!=NUMBER)&&(curType!=DOT)&&(sb.length()>0)){
         stack.push(new Double(Double.parseDouble(sb.toString())));
         dot=0;
         sb.setLength(0);
      }
     
      //if not number and sign should be pushed
      if(push!=null) stack.push(push);
     
      if((curType==OPERATION)||(curType==RIGHT_BRACKET)){
        popDoubleStack(stack);
      }
     
    }
   
  
   
    if(leftBrackets>0) throw new IllegalArgumentException("unmatched brackets!");
    if(!isEndType(curType)) throw new IllegalArgumentException("invalid end char");
    if((curType==NUMBER)&&(sb.length()>0)){
     stack.push(new Double(Double.parseDouble(sb.toString())));
       sb.setLength(0);
    }
   
    double result=((Double)stack.pop()).doubleValue();
    while(!stack.empty()){
     Operation op=(Operation)stack.pop();
     Double num=(Double)stack.pop();
     result=Compute.compute(num.doubleValue(),result,op);     
    }
    return result;
  }
 
  public static int parseInt(String expression) throws ParseException {
    
     //here use | not || just for the simplity
     //do you know why?
     if ((expression == null) | (expression=expression.trim()).equals("")) {
       throw new NullPointerException("expression can't be null or blank!");
     }
 
  //remember the priority so as to save the pop stack times
  //int prePriority=0;
  //int curPriority=0;
  Stack stack=new Stack();
  int curType=NULL;
  boolean isNegative=false;
  int leftBrackets=0;
    
     StringBuffer sb=new StringBuffer();
    
     for (int i = 0; i < expression.length(); i++) {
       Object push=null;
       char c = expression.charAt(i);
      //ignore blank
      while(c==' '){
       i++;
       c=expression.charAt(i);
      }
      //check valid char
      checkValidCharForInt(c,i);
       
       switch (c) {
        case '+':
        case '-':
         checkExpect(curType,OPERATION+SIGN,i);
         //the operation must after number or )
         if((curType==NUMBER)||(curType==RIGHT_BRACKET)){
          curType=OPERATION;
          if(c=='+') push=Operation.PLUS;
          else push=Operation.MINUS;
         }
         //sign must after ( or at the begining.
         else{
          curType=SIGN;
          if(c=='-') isNegative=true;
          else isNegative=false;
         }
            break;
        case '*':
        case '/':
        case '%':
          checkExpect(curType,OPERATION,i);
          if(c=='*') push=Operation.MULTIPLY;
          else if(c=='/') push=Operation.DIVIDE;
          else push=Operation.MOD;
                    
          curType=OPERATION;
           break;
        case '(':
         checkExpect(curType,LEFT_BRACKET,i);
         push=Bracket.LEFT;
         
         curType=LEFT_BRACKET;
         leftBrackets++;
         break;
        case ')':
         checkExpect(curType,RIGHT_BRACKET,i);
         push=Bracket.RIGHT;
         
         curType=RIGHT_BRACKET;
         leftBrackets--;
         if(leftBrackets<0) throw new IllegalArgumentException("unmatched right bracket at inidex "+i);
         break;
        default:
            //must be number
            checkExpect(curType,NUMBER,i);
            sb.append(c);
      curType=NUMBER;    
        
      }
     
     
      //if it is a negative sign then push number -1 and *
      if((curType==SIGN)&&(isNegative)){
       stack.push(new Integer(-1));
       stack.push(Operation.MULTIPLY);
      }
     
     
      // read a number
      if((curType!=NUMBER)&&(sb.length()>0)){
         stack.push(new Integer(Integer.parseInt(sb.toString())));
         sb.setLength(0);
      }
     
      //if not number and sign should be pushed
      if(push!=null) stack.push(push);
     
      if((curType==OPERATION)||(curType==RIGHT_BRACKET)){
        popIntStack(stack);
      }
     
    }
   
  
   
    if(leftBrackets>0) throw new IllegalArgumentException("unmatched brackets!");
    if(!isEndType(curType)) throw new IllegalArgumentException("invalid end char");
    if((curType==NUMBER)&&(sb.length()>0)){
     stack.push(new Integer(Integer.parseInt(sb.toString())));
       sb.setLength(0);
    }
   
    int result=((Integer)stack.pop()).intValue();
    while(!stack.empty()){
     Operation op=(Operation)stack.pop();
     Integer num=(Integer)stack.pop();
     result=Compute.compute(num.intValue(),result,op);     
    }
    return result;
  }
 
  private static void popIntStack(Stack s){
    Object obj=s.pop();
    //if it is ) then pop
    if(obj==Bracket.RIGHT){
     //must be number,becaurse the stack can have no more than 1 right brackets 
     Integer i_1=(Integer)s.pop();
     Object  op_1=s.pop();
     if(op_1==Bracket.LEFT){
      //push back and return;
      s.push(i_1);
      return;
     }
     //op must be Operation here
     //next must be number
     Integer i_2=(Integer)s.pop();
     
     //compute
     int result=Compute.compute(i_2.intValue(),i_1.intValue(),(Operation)op_1);
         
     s.push(new Integer(result));
     s.push(Bracket.RIGHT);
     //recruitive;
     popIntStack(s);
    }
    //operation +,-,*,/,%
    else if(obj instanceof Operation){
     //must be Number
     Operation op_1=(Operation)obj;
     Integer i_1=(Integer)s.pop();
     
     //if it is empty
     if(s.empty()){
    s.push(i_1);
    s.push(op_1);
    return;          
     }
     
     Object op_2=s.pop();
     
     //can't compute if it is left bracket or the pre has the lower Priority
     if((op_2==Bracket.LEFT)||
      (((Operation)op_2).getPriority()<op_1.getPriority())){
      //push back and return
      s.push(op_2);
      s.push(i_1);
      s.push(op_1);
      return;
     }
     //op_2 must be Operation here
     //and next must be number
    
     Integer i_2=(Integer)s.pop();
     
     int result=Compute.compute(i_2.intValue(),i_1.intValue(),(Operation)op_2);
     s.push(new Integer(result));
     s.push(op_1);
     popIntStack(s);      
    }
 
 }
 private static void popDoubleStack(Stack s){
    Object obj=s.pop();
    //if it is ) then pop
    if(obj==Bracket.RIGHT){
     //must be number,becaurse the stack can have no more than 1 right brackets 
     Double d_1=(Double)s.pop();
     Object  op_1=s.pop();
     if(op_1==Bracket.LEFT){
      //push back and return;
      s.push(d_1);
      return;
     }
     //op must be Operation here
     //next must be number
     Double d_2=(Double)s.pop();
     
     //compute
     double result=Compute.compute(d_2.doubleValue(),d_1.doubleValue(),(Operation)op_1);
         
     s.push(new Double(result));
     s.push(Bracket.RIGHT);
     //recruitive;
     popDoubleStack(s);
    }
    //operation +,-,*,/,%
    else if(obj instanceof Operation){
     //must be Number
     Operation op_1=(Operation)obj;
     Double d_1=(Double)s.pop();
     
     //if it is empty
     if(s.empty()){
    s.push(d_1);
    s.push(op_1);
    return;          
     }
     
     Object op_2=s.pop();
     
     //can't compute if it is left bracket or the pre has the lower Priority
     if((op_2==Bracket.LEFT)||
      (((Operation)op_2).getPriority()<op_1.getPriority())){
      //push back and return
      s.push(op_2);
      s.push(d_1);
      s.push(op_1);
      return;
     }
     //op_2 must be Operation here
     //and next must be number
    
     Double d_2=(Double)s.pop();
     
     double result=Compute.compute(d_2.doubleValue(),d_1.doubleValue(),(Operation)op_2);
     s.push(new Double(result));
     s.push(op_1);
     popDoubleStack(s);      
    }
 
 }
}


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值