写了一个包含四则运算和小括号的类,可以输入一个长串的算式,根据四则运算和小括号的运算顺序,计算出最终值,并按照脱式计算格式打印步骤:
输入: +1-(- (2*+5)/-2)+9×3 输出 +1-(-(2×+5)÷-2)+9×3 =1-(-(2×5)÷-2)+9×3 =1-(10÷2)+9×3 =1-5+9×3 =1-5+27 =-4+27 =23最终代码:
importjava.util.ArrayList;importjava.util.List;importjava.util.regex.Pattern;publicclassComputor{privatestaticfinalStringLEFT_BRACKET="(";privatestaticfinalStringRIGHT_BRACKET=")";privatestaticfinalStringADD="+";privatestaticfinalStringSUB="-";privatestaticfinalStringMUL="×";privatestaticfinalStringDIV="÷";privatefinalList<String>list=newArrayList<>();publicvoidinputFormula(Stringformula){try{//将计算机运算符改成数学运算符,把中文括号改成英文括号,把空格去掉formula=formula.replace("*",MUL).replace("/",DIV).replace("(",LEFT_BRACKET).replace(")",RIGHT_BRACKET).replaceAll("\\s*","");list.add(formula);//先把运算符连用的情况改善一下StringtoChange=opChange(formula);if(!toChange.equals(formula)){printLog(true,toChange);}//开始计算bracketComputer(formula,true);//打印运算步骤for(Stringstep:list){System.out.println(step);}}catch(Exceptione){System.err.println("计算出错");}}//将小括号拆出来,再做四则运算privateStringbracketComputer(Stringformula,booleanisLog){//算式中若是没有括号,就按照四则运算法则开始计算if(!formula.contains(RIGHT_BRACKET)){returnfourRulesComputer(formula,isLog);}//先从左边找到第一个右括号,再从这个右括号往左找左括号,这样就能找到最里层的一对括号,以及括号包含的式子intrightBracketIndex=formula.indexOf(RIGHT_BRACKET);intleftBracketIndex=formula.lastIndexOf(LEFT_BRACKET,rightBracketIndex);StringunitFormula=formula.substring(leftBracketIndex,rightBracketIndex+1);//找到的式子两边还包含了一对括号,应当去除。然后再按照四则运算法则开始运算StringdelBracket=unitFormula.substring(1,unitFormula.length()-1);StringunitResult=fourRulesComputer(delBracket,false);//把运算结果与替换现在的这个括号里的内容,组成一个新的公式,这样就减少了一对括号unitResult=formula.replace(unitFormula,unitResult);//记录一下这个式子的运算之后的式子,相当于做一个脱式计算printLog(isLog,opChange(unitResult));//一个公式可能不止一对括号,所以还需要直接递归,查找是否有下一对括号returnbracketComputer(unitResult,isLog);}//四则运算privateStringfourRulesComputer(Stringformula,booleanisLog){formula=opChange(formula);//根据四则运算法则,从左往右查找应优先运算的运算符,如果没有获取到运算符,则认为公式只剩一个数字,即只剩运算结果Stringop=getOperation(formula);if(op.isEmpty())returnformula;//查找运算符的所在位置,及其两边参与运算的数据,组成最小的运算步骤。//从下标1开始找,是因为可能当formula=-1-2,从下标1开始找,就可以略过左边那个负号intopIndex=formula.indexOf(op,1);StringleftNum=searchNum(formula,opIndex,-1);StringrightNum=searchNum(formula,opIndex,1);//运算结果StringunitResult=computer(leftNum,op,rightNum);//记录下当前步骤运算完成后的公式StringunitFormula=leftNum+op+rightNum;printLog(isLog,formula.replace(unitFormula,unitResult));//算完一步之后,继续递归算下一步骤returnfourRulesComputer(formula.replace(unitFormula,unitResult),isLog);}//把连续出现的两个运算符根据负负得正法则变成一个privateStringopChange(Stringformula){StringmulSub=MUL+SUB;StringdivSub=DIV+SUB;StringaddSub=ADD+SUB;StringsubSub=SUB+SUB;StringmulAdd=MUL+ADD;StringdivAdd=DIV+ADD;StringbracketAdd=LEFT_BRACKET+ADD;Stringchange=formula;if(formula.contains(mulSub)){//如果出现×-,就把-移到运算符左边那个数的前面intopIndex=formula.lastIndexOf(mulSub);StringleftNum=searchNum(formula,opIndex,-1);change=formula.replace(leftNum+mulSub,SUB+leftNum+MUL);}elseif(formula.contains(divSub)){//如果出现÷-,就把-移到运算符左边那个数的前面intopIndex=formula.lastIndexOf(divSub);StringleftNum=searchNum(formula,opIndex,-1);change=formula.replace(leftNum+divSub,SUB+leftNum+DIV);}elseif(formula.contains(addSub)){//把+-变成-change=formula.replace(addSub,SUB);}elseif(formula.contains(subSub)){//把--变成+change=formula.replaceFirst(subSub,ADD);}elseif(formula.contains(mulAdd)){//把×+变成×。被替换的字体需要转义一下,否则+会被当做正则表达式使用change=formula.replaceFirst(MUL+"\\"+ADD,MUL);}elseif(formula.contains(divAdd)){//把÷+变成÷。被替换的字体需要转义一下,否则+会被当做正则表达式使用change=formula.replaceFirst(DIV+"\\"+ADD,DIV);}elseif(formula.contains(bracketAdd)){//把(+变成(。被替换的字体需要转义一下,否则+会被当做正则表达式使用change=formula.replaceFirst("\\"+LEFT_BRACKET+"\\+",LEFT_BRACKET);}elseif(formula.startsWith("+")){//用正则把算式最前面的+移除change=change.substring(1);}else{//返回合适的算式returnchange;}returnopChange(change);}//根据运算符的下标,寻找运算符左右两边的数字,direction == -1查找左边的数字,direction == 1查找右边的数字privateStringsearchNum(Stringformula,intstartIndex,intdirection){if(direction==-1){//找运算符号左边的数字for(inti=startIndex+direction;i>=0;i--){Stringnum=formula.substring(i,startIndex);//遇到其它的运算符号就相当于找全了这个数字if(isNonNum(num)){//可能算式的第一个数字还包含了负号,查找数字的时候是不能把负号给落下的if(i==0&&formula.charAt(i)=='-'){returnnum;}else{returnnum.substring(1);}}}//遍历完字符串都没找到符号,说明左边没有其它的运算符了returnformula.substring(0,startIndex);}else{//找运算符号右边的数字startIndex++;for(inti=startIndex+direction;i<=formula.length();i++){Stringnum=formula.substring(startIndex,i);//遇到其它的运算符号就相当于找全了这个数字,可以直接返回了if(isNonNum(num)){returnnum.substring(0,num.length()-1);}}//遍历完字符串都没找到符号,说明右边没有其它的运算符了returnformula.substring(startIndex);}}//获取此步需要执行的运算符,有乘除的要先算乘除,乘除都有,则从左往右算,否则算加减,加减若也都有,也是从左往右算privateStringgetOperation(Stringformula){if(formula.contains(MUL)||formula.contains(DIV)){intmulIndex=formula.indexOf(MUL);intdivIndex=formula.indexOf(DIV);if(mulIndex==-1&&divIndex>=0){returnDIV;}elseif(mulIndex>=0&&divIndex==-1){returnMUL;}else{returnmulIndex<divIndex?MUL:DIV;}}elseif(formula.indexOf(ADD,1)>0||formula.indexOf(SUB,1)>0){//略过算式最左边可能是负号的情况intaddIndex=formula.indexOf(ADD,1);intsubIndex=formula.indexOf(SUB,1);if(addIndex==-1&&subIndex>=0){returnSUB;}elseif(addIndex>=0&&subIndex==-1){returnADD;}else{returnaddIndex<subIndex?ADD:SUB;}}return"";}//根据运算符,把两个数进行运算privateStringcomputer(Stringleft,Stringop,Stringright){if(left.isEmpty())returnop+right;floatleftNum=Float.parseFloat(left);floatrightNum=Float.parseFloat(right);floatresult=switch(op){caseMUL->leftNum*rightNum;caseDIV->leftNum/rightNum;caseADD->leftNum+rightNum;caseSUB->leftNum-rightNum;default->0;};returnstripTrailingZeros(result+"");}//判断是不是数字privatebooleanisNonNum(Stringformula){Patternpattern=Pattern.compile("[0123456789.]*");return!pattern.matcher(formula).matches();}//去除小数点后面多余的0privateStringstripTrailingZeros(Stringnum){returnnum.replaceAll("0+$","").replaceAll("\\.$","");}//记录运算过程privatevoidprintLog(booleanisLog,Stringlog){if(isLog){list.add("="+log);}}}