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