分析過程
分析運算的幾種情況:
- 帶有括號(不考慮大,小,中括號,統稱括號) 例如3*(2-1)
- 帶負數,例如3+(-2)
- 其他正常的情況
運算情況:
- 運算符優先級考慮,這個很明顯,先“*”,“/”,再"+","-"最后是括號
計算不帶字符串的計算,我采用了2個棧來存放,一個棧存放符號,另一個存放數字,當存放符號時發現,當前的符號比棧頂得符號優先級低或者相等,就講棧中的數據進行計算。例如 a+b-c,按照正常順序,存放“-”是,數字棧中存放有a.b,而符號棧中存放有“+”,此時,進行判斷,發現“+”與“-”優先級相等,于是計算 a +b的值(假設a+b=d).計算后數字棧中將存放d,而符號棧將只存放"-".以此類推。
package com.example.cmcc.util;
import java.math.BigDecimal;
import java.util.Stack;
/**
* <pre>
* author : lzy
* e-mail : zanyang.lin@newbeeair.com
* time : 2017/05/16
* desc :
* </pre>
*/
public class StringCaculate {
private Stack<BigDecimal> numbers = new Stack<BigDecimal>();
private Stack<Character> chs = new Stack<Character>();
/**
* 比較當前操作符與棧頂元素操作符優先級,如果比棧頂元素優先級高,則返回true,否則返回false
*
* @param str 需要進行比較的字符
* @return 比較結果 true代表比棧頂元素優先級高,false代表比棧頂元素優先級低
*/
private boolean compare(char str) {
if (chs.empty()) {
// 當為空時,顯然 當前優先級最低,返回高
return true;
}
char last = (char) chs.lastElement();
switch (str) {
case '*': {
// '*/'優先級只比'+-'高
if (last == '+' || last == '-')
return true;
else
return false;
}
case '/': {
if (last == '+' || last == '-')
return true;
else
return false;
}
// '+-'為最低,一直返回false
case '+':
return false;
case '-':
return false;
}
return true;
}
public BigDecimal caculate(String st) {
StringBuffer sb = new StringBuffer(st);
StringBuffer num = new StringBuffer();
String tem = null;
char next;
while (sb.length() > 0) {
tem = sb.substring(0, 1);// 獲取字符串的第一個字符
sb.delete(0, 1);
if (isNum(tem.trim())) {
num.append(tem);// 如果是數字,將其放入num當中
} else {
if (num.length() > 0 && !"".equals(num.toString().trim())) {// 當截取的字符不是數字時,則認為num中放置的時一個完整的數字,
// 如123+1,當獲取到+時,前面的123可以認為是一個完整的數
BigDecimal bd = new BigDecimal(num.toString().trim());
numbers.push(bd);
num.delete(0, num.length());
}
// 如果chs為空,這認為這時第一個字符直接放入
if (!chs.isEmpty()) {
// 當當前的運算符優先級等于或者小于棧頂得預算符時,做運算.
// 例如,1+2+3,當截取到2,3之間的“+”與1,2之間的"+"優先級相等時,可以先計算1+2,使其變成3+3
// 同樣,1*2+3,當截取到2,3之間的“+”與1,2之間的"*"優先級小,可以先計算1*2,使其變成2+3
while (!compare(tem.charAt(0))) {
caculate();
}
}
// 當數字棧也為空時,既運算式的第一個數字為負數時
if (numbers.isEmpty()) {
num.append(tem);
} else {
chs.push(new Character(tem.charAt(0)));
}
// 判斷后一個字符是否為“-”號,為"-"號時,認為數字為負數
// 例如 1*2*(-5),因為此運算不計算(),因此將被改寫為1*2*-5,如此情況,須將"-"認為是負數表達式而非減號
next = sb.charAt(0);
if (next == '-') {
num.append(next);
sb.delete(0, 1);
}
}
}
// 由于前面將數字放入棧時,是通過獲取符號為時處理,導致最后一個數字沒有放入棧中,因此將最后的數字放入棧中
BigDecimal bd = new BigDecimal(num.toString().trim());
numbers.push(bd);
// 此時符號棧上最多只有2個符號,并且棧頂得符號優先級高,做運算
while (!chs.isEmpty()) {
caculate();
}
return numbers.pop();
}
BigDecimal result = null;// 運算結果
private void caculate() {
BigDecimal b = numbers.pop();// 第二個運算數
BigDecimal a = null;// 第一個運算數
a = numbers.pop();
char ope = chs.pop();
switch (ope) {
// 如果是加號或者減號,則
case '+':
result = a.add(b);
// 將操作結果放入操作數棧
DebugLog.e(">>>>>>>>>>>>>" + result);
numbers.push(result);
break;
case '-':
// 將操作結果放入操作數棧
result = a.subtract(b);
DebugLog.e(">>>>>>>>>>>>>" + result);
numbers.push(result);
break;
case '*':
result = a.multiply(b);
DebugLog.e(">>>>>>>>>>>>>" + result);
// 將操作結果放入操作數棧
numbers.push(result);
break;
case '/':
result = a.divide(b);// 將操作結果放入操作數棧
DebugLog.e(">>>>>>>>>>>>>" + result);
numbers.push(result);
break;
}
}
public String getResult() {
return result.toString();
}
private boolean isNum(String num) {
return num.matches("[0-9]");
}
/**
* 功能描述。
* 解析,將帶有括號的運算符變成沒有帶括號的字運算
*/
public BigDecimal parse(String st) {
int start = 0;
StringBuffer sts = new StringBuffer(st);
int end = -1;
while ((end = sts.indexOf(")")) > 0) {
String s = sts.substring(start, end + 1);
int first = s.lastIndexOf("(");
BigDecimal value = caculate(sts.substring(first + 1, end));
sts.replace(first, end + 1, value.toString());
}
DebugLog.e(">>>>>>>>>>>>>>>>>>>>" + sts.toString());
return caculate(sts.toString());
}
}