public static void main(String args[]){ Formula f = new Formula("1*3+5+5*6/8-23+6+14+12*3-6*4"); //3+5+3.75-23+6+14+36-24 =20.75 System.out.println(f.getValue()); }
public double getValue(){
int firstHigh=0 ; //这个参数用来临时存储找出来第一个高优先级操作符的索引值 while (this.listOperator.size() > 0 ){ //如果操作符列表还有值代表运算没有最终完成
if (this.highOperateNum>0){ //如果高优先值运算符的数量不为0,就先根据高优先级运算符计算
import java.util.List;
/**
* 这个类用来包装一段仅包括数字,+-/*和小数点.的字符串。
* 由于正则式写的比较简单,所以不支持负号-,所有的-都被认为是减号。
* 该类在计算表达式的时候遵循的策略是先将高优先级的运算(*与/)计算完毕再进行+-运算。
* 比如 1+3+4*5+4/2,该类具体计算过程为
* 1、先分解表达式,存为两个list "134542"和"++*+/",并纪录高优先级运算符数量为2
* 2、在存运算符的list的size不为0的情况下,将高优先级的运算计算 即先算 4*5 ,然后再 4/2 ,把式子转成1+3+20+2
* 3、依次计算全部是+-运算的式子
*/
class Formula{
private List<Double> listNumbers; //这个list纪录所有的要计算的值
private List<String> listOperator; //这个list纪录所有的操作符
private int highOperateNum = 0; //这个值标记着当前还有多少高级别的操作符,将会优先计算这些运算符相关的式子。
Formula(String strOri){
//由于在计算过程中,在计算一个式子后,需要更新list,用LinkedList比较好。
listNumbers = new LinkedList<Double>();
listOperator = new LinkedList<String>(); this.formatOri(strOri);
}
/**
* @param strOri 目标字符串
* 这个方法用来将字符串分解,注意这里没有验证字符串的有效性。
* 如果要添加对符号的支持,请修改这个方法中的具体实现。
*/
private void formatOri(String strOri){
String[] numTemp;
String[] optTemp;
numTemp = strOri.split("[\\+\\-\\*/]") ; //根据+-*/号分解字符串,
for(int i=0 ; i<numTemp.length ; i++){
listNumbers.add(Double.valueOf(numTemp[i]));
}
optTemp = strOri.split("[0-9\\.]+");//根据数字和小数点分解字符串
for(int i=1 ; i<optTemp.length ; i++){
listOperator.add(optTemp[i]);
if (optTemp[i].equals("*") || optTemp[i].equals("/")){
this.highOperateNum++ ;
}
}
}
public static void main(String args[]){
Formula f = new Formula("1*3+5+5*6/8-23+6+14+12*3-6*4"); //3+5+3.75-23+6+14+36-24 =20.75
System.out.println(f.getValue());
}
public double getValue(){
int firstHigh=0 ; //这个参数用来临时存储找出来第一个高优先级操作符的索引值
while (this.listOperator.size() > 0 ){ //如果操作符列表还有值代表运算没有最终完成
if (this.highOperateNum>0){ //如果高优先值运算符的数量不为0,就先根据高优先级运算符计算
firstHigh = this.listOperator.indexOf("*"); //尝试寻找第一个*的index
firstHigh = (firstHigh==-1?this.listOperator.indexOf("/"):firstHigh) ;//防止只剩下除法
if (firstHigh == -1) return Double.NaN; //this.highOperateNum>0时,firstHigh不应该为0
this.perpareReckon(firstHigh); //尝试计算 }else{
this.reckon(0); //直接计算
}
}
return this.listNumbers.get(0).doubleValue();
} /**
* @param index 表明要尝试计算的运算符位置.
* 该方法主要为了处理当前运算符为*,但是前面还有个/的及类似的情况(递归调用perpareReckon(index-1))
*/
private void perpareReckon(int index){
if (this.listOperator.get(index).equals("*")||this.listOperator.get(index).equals("/")){
if (index>0){
if (this.listOperator.get(index-1).equals("+") || this.listOperator.get(index-1).equals("-")){
this.reckon(index);
}
if( this.listOperator.get(index-1).equals("*") || this.listOperator.get(index-1).equals("/")){
this.perpareReckon( index-1);
}
}else{
this.reckon(index);
}
}
}
/**
* @param optPos 运算符位置
* @return 运算结果
* 该方法根据运算位置,分别取出运算值和运算符位置进行计算
*/
private void reckon(int optPos){
double temp=0 ;
if (this.listOperator.get(optPos).equals("*")){
temp = this.listNumbers.get(optPos).doubleValue() * this.listNumbers.get(optPos+1).doubleValue();
System.out.println(this.listNumbers.get(optPos).doubleValue()+"*"+ this.listNumbers.get(optPos+1).doubleValue() + "="+temp);
updateList(optPos , Double.valueOf(temp)) ;
this.highOperateNum--;
}else if (this.listOperator.get(optPos).equals("/")){
temp = this.listNumbers.get(optPos).doubleValue() / this.listNumbers.get(optPos+1).doubleValue();
System.out.println(this.listNumbers.get(optPos).doubleValue()+"/"+ this.listNumbers.get(optPos+1).doubleValue() + "="+temp);
updateList(optPos , Double.valueOf(temp)) ;
this.highOperateNum--;
}else if (this.listOperator.get(optPos).equals("+")){
temp = this.listNumbers.get(optPos).doubleValue() + this.listNumbers.get(optPos+1).doubleValue();
System.out.println(this.listNumbers.get(optPos).doubleValue()+"+"+ this.listNumbers.get(optPos+1).doubleValue() + "="+temp);
updateList(optPos , Double.valueOf(temp)) ;
}else if (this.listOperator.get(optPos).equals("-")){
temp = this.listNumbers.get(optPos).doubleValue() - this.listNumbers.get(optPos+1).doubleValue();
System.out.println(this.listNumbers.get(optPos).doubleValue()+"-"+ this.listNumbers.get(optPos+1).doubleValue() + "="+temp);
updateList(optPos , Double.valueOf(temp)) ;
}else{
System.out.println("ERROR!!!!");
}
}
/**
* @param index 要在list中删除的值的index,以及
* @param value 要新添加的值
* 该方法用来在进行一次计算后,更新list.
*/
private void updateList(int index , Double value){
this.listNumbers.remove(index+1);
this.listNumbers.remove(index);
this.listNumbers.add(index,value);
this.listOperator.remove(index);
}
public void cls(){
this.highOperateNum = 0 ;
this.listNumbers.clear();
this.listOperator.clear();
}
}
/**
* 这个类在Formula的基础上添加了处理括号的能力。该类会把每个带括号的式子进行分解,
* 每个括号的内容作为一个Formula实例来计算结果,并将结果合并到上一级的括号内。 *
*/
public class FormulaS {
FormulaS(){}
/**
* @param str
* @return
* 该类用来验证字符串格式。当前没有验证。直接返回true
*/
private boolean validate(String str){return true;}
public double getValue(String strOri){
if (!this.validate(strOri)) return Double.NaN ;
int prev = -1 ;
int next = -1 ;
while ((prev=strOri.lastIndexOf('(')) != -1){
StringBuffer sb = new StringBuffer();
sb.append(strOri.substring(0, prev));
Formula f = new Formula(strOri.substring(prev+1, (next=strOri.indexOf(')'))));
sb.append(f.getValue());
sb.append(strOri.substring(next+1));
f.cls();
System.out.println("完成一个括号内部的计算");
strOri = sb.toString() ;
}
return new Formula(strOri).getValue();
}
public static void main(String[] args) { String str = "3+3-3*3/3*(2+2-2*2/2*(4+4-4*4/4)+5+5)+10+20-10" ;
//第一次计算后的结果"3+3-3*3/3*(2+2-2*2/2*4+5+5)+10+20-10"
//第二次计算后的结果"3+3-3*3/3*6+10+20-10"
FormulaS fs = new FormulaS();
System.out.println("最后的运算结果为:"+fs.getValue(str));
}
}