数字表达式解析器

原创 2004年12月29日 08:54:00

昨天匆忙写完的,估计还有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);      
    }
 
 }
}


 

表达式解析计算器源码(完整实现)

大一下时做的大数非图形界面计算器,自己在这个过程中收获较大,希望和大家分享下 分三个(面向过程浮点版,面向对象浮点版和面向对象大数版)版本:: 完整实现如下: Version1: 面向过程浮点版 (从...
  • David_Jett
  • David_Jett
  • 2015年01月27日 20:44
  • 1494

[编译原理] 简单的词法分析器

本文是网易云课堂中国科学技术大学华保健老师教授的《编译原理》课程习题。 1 题目 在这部分中,你将使用图转移算法手工实现一个小型的词法分析器。 分析器的输入:存储在文本文件中的字符...
  • jitianyu123
  • jitianyu123
  • 2017年06月19日 15:13
  • 711

数独解析器

  • 2013年05月29日 22:49
  • 25KB
  • 下载

Qt计算器开发(一):后缀表达式实现完整数学表达式的计算

相信学过数据结构的人都听说过后缀表达式,就是在学习栈的时候。相信大家也都用过计算器windows里面的calc。但是有没发现它只能单步计算,而不能一次计算一个表达式。后缀表达式就有了用武之地,可以一次...
  • guodongxiaren
  • guodongxiaren
  • 2014年04月28日 17:51
  • 4683

Java解析字符串表达式--逆波兰表达式的计算

问题来由: 读入一个字符串形式的四则运算表达式,输出对应的计算结果。如读入的是“6 * ( 5 + ( 2 + 3) * 8 + 3)”,那么解析后的输出结果应为288。 思路: 一般的计...
  • bruce_6
  • bruce_6
  • 2014年09月10日 16:17
  • 2703

C#实现的表达式解析与计算类TExprParser介绍

介绍一组C#实现的包括算术、关系、逻辑、自定义函数和占位符的表达式解析与计算类TExprParser,dll和测试程序请到http://download.csdn.net/user/hulihui下载...
  • hulihui
  • hulihui
  • 2015年02月14日 00:13
  • 3204

算术表达式动态解析器

  • 2010年04月11日 17:18
  • 48KB
  • 下载

表达式解析器

  • 2004年09月02日 10:08
  • 230KB
  • 下载

算术表达式解析器

  • 2006年03月16日 00:00
  • 49KB
  • 下载

Java编程艺术-表达式解析器.rar

  • 2007年06月22日 11:39
  • 65KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:数字表达式解析器
举报原因:
原因补充:

(最多只允许输入30个字)