You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
201 lines
5.3 KiB
201 lines
5.3 KiB
/*******************************************************************************
|
|
* 本软件作品的著作权、商标权等知识产权属于上海锐道信息技术有限公司(http://www.bstek.com)所有,
|
|
* 任何单位和个人未经上海锐道信息技术有限公司书面授权,不得以任何目的、任何方式复制、传播本软件作品的任何部分,
|
|
* 否则将视为侵权,上海锐道信息技术有限公司保留依法追究其法律责任的权利。
|
|
******************************************************************************/
|
|
package com.bstek.ureport.utils;
|
|
|
|
import java.math.BigDecimal;
|
|
import java.math.RoundingMode;
|
|
import java.util.Stack;
|
|
|
|
/*******************************************************************************
|
|
* Copyright 2017 Bstek
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
* use this file except in compliance with the License. You may obtain a copy
|
|
* of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations under
|
|
* the License.
|
|
******************************************************************************/
|
|
import com.bstek.ureport.Utils;
|
|
|
|
/**
|
|
* @author Jacky.gao
|
|
* @since 2018年6月28日
|
|
*/
|
|
public class ElCompute {
|
|
private Stack<Object> dataStack=new Stack<Object>();
|
|
private Stack<Character> operateStack=new Stack<Character>();
|
|
public static void main(String[] args) {
|
|
long start=System.currentTimeMillis();
|
|
String expr="(2+20)*3-10+\"super man\"";
|
|
for(int i=0;i<1;i++) {
|
|
ElCompute el=new ElCompute();
|
|
Object data=el.doCompute(expr);
|
|
System.out.println(data);
|
|
}
|
|
long end=System.currentTimeMillis();
|
|
System.out.println(end-start);
|
|
}
|
|
|
|
public Object doCompute(String expr) {
|
|
init(expr);
|
|
return dataStack.pop();
|
|
}
|
|
private void init(String expr){
|
|
StringBuilder dataSb=new StringBuilder();
|
|
char prevQuote='0';
|
|
for(int i=0;i<expr.length();i++){
|
|
char c=expr.charAt(i);
|
|
switch(c){
|
|
case '+':
|
|
addDataStack(dataSb);
|
|
doCalculate(0);
|
|
operateStack.push(c);
|
|
break;
|
|
case '-':
|
|
doMinus(dataSb, prevQuote);
|
|
break;
|
|
case '*':
|
|
addDataStack(dataSb);
|
|
doCalculate(2);
|
|
operateStack.push(c);
|
|
break;
|
|
case '/':
|
|
addDataStack(dataSb);
|
|
doCalculate(2);
|
|
operateStack.push(c);
|
|
break;
|
|
case '%':
|
|
addDataStack(dataSb);
|
|
doCalculate(2);
|
|
operateStack.push(c);
|
|
break;
|
|
case '(':
|
|
operateStack.push(c);
|
|
break;
|
|
case ')':
|
|
addDataStack(dataSb);
|
|
doCalculate(1);
|
|
break;
|
|
case '"':
|
|
if(prevQuote=='"'){
|
|
prevQuote='0';
|
|
dataStack.push(dataSb.toString());
|
|
dataSb.setLength(0);
|
|
}else{
|
|
prevQuote='"';
|
|
}
|
|
break;
|
|
case ' ':
|
|
if(prevQuote=='"') {
|
|
dataSb.append(c);
|
|
}
|
|
break;
|
|
default:
|
|
dataSb.append(c);
|
|
}
|
|
}
|
|
if(dataSb.length()>0){
|
|
addDataStack(dataSb);
|
|
}
|
|
doCalculate(0);
|
|
}
|
|
|
|
private void doMinus(StringBuilder dataSb,char prevQuote){
|
|
if(dataSb.length()==0){
|
|
dataSb.append('-');
|
|
}else{
|
|
addDataStack(dataSb);
|
|
doCalculate(0);
|
|
operateStack.push('-');
|
|
}
|
|
}
|
|
|
|
|
|
private void doCalculate(int current) {
|
|
if(operateStack.empty()){
|
|
return;
|
|
}
|
|
char prevOp=operateStack.peek();
|
|
if(prevOp=='('){
|
|
return;
|
|
}
|
|
if(current==0 || current==1){
|
|
char op=operateStack.pop();
|
|
do{
|
|
Object right=dataStack.pop();
|
|
Object left=dataStack.pop();
|
|
Object result=calculate(left, op, right);
|
|
dataStack.push(result);
|
|
if(operateStack.isEmpty()){
|
|
break;
|
|
}
|
|
op=operateStack.pop();
|
|
}while(op!='(');
|
|
}else if(current==2){
|
|
while(prevOp=='*' || prevOp=='/' || prevOp=='%') {
|
|
Object right=dataStack.pop();
|
|
Object left=dataStack.pop();
|
|
char op=operateStack.pop();
|
|
Object result=calculate(left, op, right);
|
|
dataStack.push(result);
|
|
if(operateStack.isEmpty()){
|
|
break;
|
|
}
|
|
prevOp=operateStack.peek();
|
|
if(prevOp=='('){
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private Object calculate(Object left,char op,Object right){
|
|
if((op=='*' || op=='/' || op=='%' || op=='-')){
|
|
if(right instanceof String || left instanceof String){
|
|
throw new RuntimeException(left + " and "+right+" can't do "+op+"!");
|
|
}
|
|
BigDecimal b1=(BigDecimal)left;
|
|
BigDecimal b2=(BigDecimal)right;
|
|
if(op=='*'){
|
|
return b1.multiply(b2);
|
|
}else if(op=='/'){
|
|
return b1.divide(b2,10,RoundingMode.HALF_UP).stripTrailingZeros();
|
|
}else if(op=='%'){
|
|
return b1.divideAndRemainder(b2)[1];
|
|
}else if(op=='-'){
|
|
return b1.subtract(b2);
|
|
}
|
|
}else if(op=='+'){
|
|
if(right instanceof String || left instanceof String){
|
|
return left.toString()+right.toString();
|
|
}else{
|
|
BigDecimal b1=(BigDecimal)left;
|
|
BigDecimal b2=(BigDecimal)right;
|
|
return b1.add(b2);
|
|
}
|
|
}
|
|
throw new RuntimeException("Unkown operate "+op+"");
|
|
}
|
|
|
|
|
|
private void addDataStack(StringBuilder dataSb) {
|
|
if(dataSb.length()==0)return;
|
|
String data=dataSb.toString();
|
|
dataSb.setLength(0);
|
|
try{
|
|
BigDecimal bd=Utils.toBigDecimal(data);
|
|
dataStack.push(bd);
|
|
}catch(Exception ex){
|
|
dataStack.push(data);
|
|
}
|
|
}
|
|
}
|
|
|