您的位置:首页 > 编程语言 > Java开发

java栈实现简单的计算器

2017-10-15 19:55 309 查看
/**
* 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(
4000
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
*/
// step1
Pattern pattern = Pattern.compile("^[-+*/%\\.].{1,}");// 匹配第一位是    +、-、*、/、. 的字符串
Matcher matcher = pattern.matcher(str);
if( matcher.matches() ) {//输出 true,验证通过
str = "0" + str;
}
System.out.println("第一步处理(表达式开头是 +、-、*、/、%、. 前面加个0)后的算式:  [ "+str+" ]");

// step2
pattern = 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+" ]");

// step3
pattern = 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) {
// test
Calculator 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 );
}

}



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: