java栈实现简单的计算器

来源:互联网 发布:双源abo乐乎 编辑:程序博客网 时间:2024/06/08 12:02
/** * java栈实现简单的计算器 * 计算表达式的值 * 实现+、-、/、*、%、(、) * #表示表达式的开始与结束 */import java.util.Stack;import java.util.Vector;import java.util.regex.Matcher;import java.util.regex.Pattern;public class Calculator {private Stack<String> operation = new Stack<String>();// 存放运算符的栈private Stack<Double> number = new Stack<Double>();// 存放数字的栈public static final String ERROR = "ERROR";public String calculator(String expression) {operation.clear();number.clear();String[] str = getCharacters(expression);for (int i = 0; i < str.length; ++i) {if(i == 0) {// 表达式错误if(str[i].equals(ERROR)) return ERROR;//第一个"#"入栈operation.add(str[i]);} else {if( isNumber(str[i]) ) {// 如果是数字//入数据栈number.add(Double.parseDouble(str[i]));}/* * 运算符入栈规则: * 1."("直接入栈,不用判断优先级 * 2.当前扫描的运算符的优先级高于运算符栈顶的运算符优先级,将当前运算符入栈 */if(isOperation(str[i])) {//入操作符栈if( "(".equals(str[i]) ) {//左括号直接入栈operation.add(str[i]);} else {if( !operation.isEmpty() ) {if(operation.isEmpty()) {number.clear();return ERROR;}String topElement = operation.peek();// 运算符栈顶元素int topElementLevel = getLevel(topElement); // 运算符栈顶元素优先级int curElementLevel = getLevel(str[i]); // 当前扫描的运算符的优先级/* * 当前扫描的运算符的优先级小于运算符栈顶的运算符优先级: * 则取出操作数栈顶前2个数和运算符栈顶符号进行运算 */while(curElementLevel < topElementLevel) {// 运算前判断if(operation.size() < 2 || number.size() < 2) {operation.clear();number.clear();return ERROR;}// 计算并将结果入栈number.add(calc(number.pop(), number.pop(), operation.pop()));// 运算完之后重新获取运算符栈顶元素topElement = operation.peek();topElementLevel = getLevel(topElement);}/* * 当前扫描的运算符的优先级等于运算符栈顶的运算符优先级: * 1.若当前扫描的运算符为"+、-、*、/、%" ,则取出操作数栈顶前2个数和运算符栈顶符号进行运算 * 2.若当前扫描的运算符为")",栈顶运算符为"(",则将括号出栈 * 3.若当前扫描的运算符为"#",说明计算完毕,得到结果 */while(curElementLevel == topElementLevel) {if( "+".equals(str[i]) || "-".equals(str[i]) || "*".equals(str[i]) || "/".equals(str[i]) || "%".equals(str[i])) {// 运算前判断if(operation.size() < 2 || number.size() < 2) {operation.clear();number.clear();return ERROR;}// 计算并将结果入栈number.add(calc(number.pop(), number.pop(), operation.pop()));// 运算完之后重新获取运算符栈顶元素topElement = operation.peek();topElementLevel = getLevel(topElement);}//左右括号抵消if( ")".equals(str[i]) && "(".equals(topElement) ) {if(operation.size() < 2) {operation.clear();number.clear();return ERROR;}// 括号出栈operation.pop();//括号出栈后重新获取运算符栈顶元素topElement = operation.peek();topElementLevel = getLevel(topElement);break ; // 不加break可以去掉多余的左括号,否则左右括号必须一一对应}if( "#".equals(str[i]) && "#".equals(topElement) ) {if(number.isEmpty()) {operation.clear();return ERROR;}//得到结果double result = number.peek();operation.clear();number.clear();return result+"";}}/* * 当前扫描的运算符的优先级大于运算符栈顶的运算符优先级且不是")", * 则将当前扫描到的运算符入栈即可 */if(curElementLevel > topElementLevel && !")".equals(str[i])) {//入栈operation.add(str[i]);}} else {number.clear();return ERROR;}}}}}return ERROR;}/**  * 对算数表达式进行初始化处理 * @param str * @return */private String init(String str){/*  * 算式处理,使用正则表达式 * 1.表达式开头的 +、-、*、/、%、. 前面加个0 * 2.连续符号剔除+、-、*、/、%、. * 3.匹配以连续多个左括号"("开头和以" +、-、."结束的字符串,在最后一个左括号的后面加上0 */// step1Pattern pattern = Pattern.compile("^[-+*/%\\.].{1,}");// 匹配第一位是    +、-、*、/、. 的字符串Matcher matcher = pattern.matcher(str);if( matcher.matches() ) {//输出 true,验证通过str = "0" + str;}System.out.println("第一步处理(表达式开头是 +、-、*、/、%、. 前面加个0)后的算式:  [ "+str+" ]");// step2pattern = Pattern.compile("[-+*/%\\.]{2,}");matcher = pattern.matcher(str);while( matcher.find() ){String group = matcher.group();String operation = group.substring(0,1);// 重复的运算符if( group.replace(operation, "").length()==0 ) {// 只剔除连续相同的运算符,否则报错str = matcher.replaceFirst(operation);matcher = pattern.matcher(str);} else return ERROR;}System.out.println("第二步处理(剔除表达式连续重复的运算符)后的算式: [ "+str+" ]");// step3pattern = Pattern.compile("[(][-+\\.]");matcher = pattern.matcher(str);int startIndex = 0;int endIndex = 0;int count=0;while( matcher.find() ) {//输出 true,验证通过startIndex = matcher.start();endIndex = matcher.end();// 加了多少个0就要将字符索引加多少startIndex += count;endIndex += count;str = str.substring(0, startIndex+1) + "0" + str.substring(endIndex-1);count++;// 记录加0的个数}System.out.println("第三步处理(左括号后面是运算符[+-.],在括号后面加0)后的算式:  [ "+str+" ]");return str;}/** *  拆分表达式 */private String[] getCharacters(String str) {// 初始化处理表达式str = init(str);if(ERROR.equals(str)){return new String[]{ERROR};}Vector<String> strs = new Vector<String>();strs.add("#");String charStr = "";int startIndex = 0;String lastStr = "";for (int i = 0; i < str.length(); ++i) {char character = str.charAt(i);if (isOperation(character)) {charStr = str.substring(startIndex, i);if(!"".equals(charStr)) {if(isNumber(charStr)) strs.add(charStr);else return new String[]{ERROR};}strs.add(character + "");startIndex += charStr.length() + 1;lastStr = str.substring(i+1);}}if(!"".equals(lastStr)) {strs.add(lastStr);}strs.add("#");int size = strs.size();String[] result = new String[size];for (int j = 0; j < size; ++j) {result[j] = strs.get(j);}System.out.println("符号与数字分隔:" + strs);strs.clear();strs = null;return result;}// 得到操作符的优先级别private int getLevel(String operate) {int level = -1;switch (operate) {case "#":level = 0;break;case "(":level = 1;break;case ")":level = 1;break;case "+":level = 2;break;case "-":level = 2;break;case "/":level = 3;break;case "%":level = 3;break;case "*":level = 4;break;}return level;}/**  * 判断是否为运算符号 * @param c * @return */private boolean isOperation(char c) {if (c == '#' || c == '(' || c == ')' || c == '+' || c == '-' || c == '*' || c == '/' || c == '%')return true;return false;}/** *  判断是否为运算符号 * @param c * @return */private boolean isOperation(String c) {if ("#".equals(c) || "(".equals(c) || ")".equals(c) || "+".equals(c) || "-".equals(c) || "*".equals(c) || "/".equals(c) || "%".equals(c))return true;return false;}/**  * 判断字符串是否为浮点型数字 * @param str * @return */private boolean isNumber(String str) {try {Double.parseDouble(str);return true;} catch (Exception e) {//e.printStackTrace();return false;}}private double calc(double number1, double number2, String operate){double result = 0;switch (operate) {case "+":result = number2 + number1;break;case "-":result = number2 - number1;break;case "*":result = number2 * number1;break;case "/":result = number2 / number1;break;case "%":result = number2 % number1;break;}return result;}public static void main(String[] args) {// testCalculator c = new Calculator();String result = c.calculator("+1*(5+(0-(5*((-10*(2+3)))))++7)+5+((-2+10)-10+15.5%5.8)*2*(-1+2)+10.5+10-10+(-122+3)+15+(50+(+5+6.5*(-2+5)/6.5))*5+(+120-8*5)+45%100");System.out.println( result );}}