## CSDN博客

### 数字表达式解析器

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){
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);
}

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);
}

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 0