分析過程
分析運(yùn)算的幾種情況:
- 帶有括號(hào)(不考慮大,小,中括號(hào),統(tǒng)稱括號(hào)) 例如3*(2-1)
- 帶負(fù)數(shù),例如3+(-2)
- 其他正常的情況
運(yùn)算情況:
- 運(yùn)算符優(yōu)先級(jí)考慮,這個(gè)很明顯,先“*”,“/”,再"+","-"最后是括號(hào)
計(jì)算不帶字符串的計(jì)算,我采用了2個(gè)棧來存放,一個(gè)棧存放符號(hào),另一個(gè)存放數(shù)字,當(dāng)存放符號(hào)時(shí)發(fā)現(xiàn),當(dāng)前的符號(hào)比棧頂?shù)梅?hào)優(yōu)先級(jí)低或者相等,就講棧中的數(shù)據(jù)進(jìn)行計(jì)算。例如 a+b-c,按照正常順序,存放“-”是,數(shù)字棧中存放有a.b,而符號(hào)棧中存放有“+”,此時(shí),進(jìn)行判斷,發(fā)現(xiàn)“+”與“-”優(yōu)先級(jí)相等,于是計(jì)算 a +b的值(假設(shè)a+b=d).計(jì)算后數(shù)字棧中將存放d,而符號(hào)棧將只存放"-".以此類推。
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>();
/**
* 比較當(dāng)前操作符與棧頂元素操作符優(yōu)先級(jí),如果比棧頂元素優(yōu)先級(jí)高,則返回true,否則返回false
*
* @param str 需要進(jìn)行比較的字符
* @return 比較結(jié)果 true代表比棧頂元素優(yōu)先級(jí)高,false代表比棧頂元素優(yōu)先級(jí)低
*/
private boolean compare(char str) {
if (chs.empty()) {
// 當(dāng)為空時(shí),顯然 當(dāng)前優(yōu)先級(jí)最低,返回高
return true;
}
char last = (char) chs.lastElement();
switch (str) {
case '*': {
// '*/'優(yōu)先級(jí)只比'+-'高
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);// 獲取字符串的第一個(gè)字符
sb.delete(0, 1);
if (isNum(tem.trim())) {
num.append(tem);// 如果是數(shù)字,將其放入num當(dāng)中
} else {
if (num.length() > 0 && !"".equals(num.toString().trim())) {// 當(dāng)截取的字符不是數(shù)字時(shí),則認(rèn)為num中放置的時(shí)一個(gè)完整的數(shù)字,
// 如123+1,當(dāng)獲取到+時(shí),前面的123可以認(rèn)為是一個(gè)完整的數(shù)
BigDecimal bd = new BigDecimal(num.toString().trim());
numbers.push(bd);
num.delete(0, num.length());
}
// 如果chs為空,這認(rèn)為這時(shí)第一個(gè)字符直接放入
if (!chs.isEmpty()) {
// 當(dāng)當(dāng)前的運(yùn)算符優(yōu)先級(jí)等于或者小于棧頂?shù)妙A(yù)算符時(shí),做運(yùn)算.
// 例如,1+2+3,當(dāng)截取到2,3之間的“+”與1,2之間的"+"優(yōu)先級(jí)相等時(shí),可以先計(jì)算1+2,使其變成3+3
// 同樣,1*2+3,當(dāng)截取到2,3之間的“+”與1,2之間的"*"優(yōu)先級(jí)小,可以先計(jì)算1*2,使其變成2+3
while (!compare(tem.charAt(0))) {
caculate();
}
}
// 當(dāng)數(shù)字棧也為空時(shí),既運(yùn)算式的第一個(gè)數(shù)字為負(fù)數(shù)時(shí)
if (numbers.isEmpty()) {
num.append(tem);
} else {
chs.push(new Character(tem.charAt(0)));
}
// 判斷后一個(gè)字符是否為“-”號(hào),為"-"號(hào)時(shí),認(rèn)為數(shù)字為負(fù)數(shù)
// 例如 1*2*(-5),因?yàn)榇诉\(yùn)算不計(jì)算(),因此將被改寫為1*2*-5,如此情況,須將"-"認(rèn)為是負(fù)數(shù)表達(dá)式而非減號(hào)
next = sb.charAt(0);
if (next == '-') {
num.append(next);
sb.delete(0, 1);
}
}
}
// 由于前面將數(shù)字放入棧時(shí),是通過獲取符號(hào)為時(shí)處理,導(dǎo)致最后一個(gè)數(shù)字沒有放入棧中,因此將最后的數(shù)字放入棧中
BigDecimal bd = new BigDecimal(num.toString().trim());
numbers.push(bd);
// 此時(shí)符號(hào)棧上最多只有2個(gè)符號(hào),并且棧頂?shù)梅?hào)優(yōu)先級(jí)高,做運(yùn)算
while (!chs.isEmpty()) {
caculate();
}
return numbers.pop();
}
BigDecimal result = null;// 運(yùn)算結(jié)果
private void caculate() {
BigDecimal b = numbers.pop();// 第二個(gè)運(yùn)算數(shù)
BigDecimal a = null;// 第一個(gè)運(yùn)算數(shù)
a = numbers.pop();
char ope = chs.pop();
switch (ope) {
// 如果是加號(hào)或者減號(hào),則
case '+':
result = a.add(b);
// 將操作結(jié)果放入操作數(shù)棧
DebugLog.e(">>>>>>>>>>>>>" + result);
numbers.push(result);
break;
case '-':
// 將操作結(jié)果放入操作數(shù)棧
result = a.subtract(b);
DebugLog.e(">>>>>>>>>>>>>" + result);
numbers.push(result);
break;
case '*':
result = a.multiply(b);
DebugLog.e(">>>>>>>>>>>>>" + result);
// 將操作結(jié)果放入操作數(shù)棧
numbers.push(result);
break;
case '/':
result = a.divide(b);// 將操作結(jié)果放入操作數(shù)棧
DebugLog.e(">>>>>>>>>>>>>" + result);
numbers.push(result);
break;
}
}
public String getResult() {
return result.toString();
}
private boolean isNum(String num) {
return num.matches("[0-9]");
}
/**
* 功能描述。
* 解析,將帶有括號(hào)的運(yùn)算符變成沒有帶括號(hào)的字運(yùn)算
*/
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());
}
}