今天在技术交流群里面碰到一个菜鸡,问关于表达式解析求值的问题,数据结构的书中一般都有这个的介绍,但一般都是前缀和后缀的表达式的方法,于是想试试自然一点的方法。
import java.util.Stack;
public class Expression {
public static void main(String[] args){
envaluate("3*8-12*(12*12/12/12)");
envaluate("4*5*20-12-30*12-(12*12/12/12)");
envaluate("4-5-5-7-8");
}
public static void envaluate(String expression) {
double result= new ExpressionReader(expression).envaluate();
System.out.println(String.format("%s=%s", expression,result));
}
}
class ExpressionReader {
char[] expression;
int pos = 0;
public ExpressionReader(String _expression) {
super();
this.expression = _expression.toCharArray();
}
public boolean hasNext() {
return pos<expression.length;
}
public char next() {
return expression[pos++];
}
public char peek() {
return expression[pos];
}
public double envaluate() {
Stack<Double> args=new Stack<Double>();
Stack<Character> ops = new Stack<Character>();
while(hasNext()){
char c = peek();
if(c=='('){
next();
double value = envaluate();
args.push(value);
}else if(c==')'){
next();
calculate(args,ops);
return args.peek();
}else if(isOperator(c)){
next();
if(c=='+' || c=='-'){
if(ops.size()>=1){
calculate(args,ops);
}
} else if(c=='*' || c=='/'){
if(ops.size()>1){
char lastOp=ops.peek();
if(lastOp=='+' || lastOp=='-'){
}else {
}
}
}
ops.push(c);
}else{
double value=readNumber();
args.push(value);
}
}
calculate(args, ops);
return args.peek();
}
public double calculate(Stack<Double> args, Stack<Character> ops){
while(args.size()>=2 && ops.size()>=1){
double b=args.pop();
double a=args.pop();
char op=ops.pop();
if(!ops.isEmpty()){
char prevOp=ops.peek();
if(priority(op)==priority(prevOp)){
if(prevOp=='/'){
op=op=='*'?'/':'*';
}else if(prevOp=='-'){
op=op=='+'?'-':'+';
}
}
}
double result = 0;
switch(op){
case '+':
result =a+b;
break;
case '-':
result =a-b;
break;
case '*':
result =a*b;
break;
case '/':
result =a/b;
break;
}
//System.out.println(String.format("%s%s%s=%s", a,op,b,result));
args.push(result);
}
return args.peek();
}
public double readNumber() {
double value=0;
double rightPower=1;
while(hasNext()){
char c=peek();
if(c=='.'){
next();
rightPower*=0.1;
}else if(Character.isDigit(c)){
next();
if(rightPower>0) {
value*=10;
value +=(c-'0');
}else {
value +=(c-'0') * rightPower;
rightPower*=0.1;
}
}else {
break;
}
}
return value;
}
public static boolean isOperator(char c){
char[] operators={'+','-','*','/'};
for(char op:operators){
if(c==op){
return true;
}
}
return false;
}
public static int priority(char op){
if(op=='+'|| op=='-'){
return 1;
}
return 2;
}
}