/** * 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
*/
// 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);
}
}
Java栈实现简单的计算器
最新推荐文章于 2025-01-12 11:40:59 发布