带括号的四则运算
public class CaculatorDemo {
public static void main(String[] args) {
String exp = "-3+6*-2-8/-4*2";//-11
String exp2 = "-3+(9+8+(8-4)/2)*2";//35
//double result = calc(exp);
double result = calcKuohao(exp2);
System.out.println(result);
result = dkuohao(exp2);
System.out.println(result);
}
/**
* 带括号的四则运算
* @param exp
* @return
*/
public static double calcKuohao(String exp){
//找最后一个左括号的下标,没找到就返回-1
int left = exp.lastIndexOf('(');
if (left == -1) {
//说明表达式无括号
return calc(exp);
}else {
//找与它相对应的右括号的下标
int right = exp.indexOf(')', left);
//找到相对应的右括号之后,取出括号中的表达式
String str = exp.substring(left + 1, right);
//对str做无括号四则运算
double d = calc(str);
//拼接
exp = exp.substring(0, left) + d + exp.substring(right + 1);
//递归去括号
return calcKuohao(exp);
}
}
/**
* 不带括号的四则运算
* @param exp
* @return
*/
public static double calc(String exp){
double result = 0;
//将负号转换成@符号
exp = fu2At(exp);
//提取数字集合
List<Double> nums = getNums(exp);
//提取运算符集合
List<Character> opts = getOpts(exp);
//先乘除
//遍历运算符集合,如果是*/就取出来
for (int i = 0; i < opts.size(); i++) {
char c = opts.get(i);
if (c == '*' || c == '/') {
opts.remove(i);//移除该运算符
//从数字集合的i的位置取出第一个数
double d1 = nums.remove(i);
//再从数字集合的i的位置取出第二个数
double d2 = nums.remove(i);
//判断运算符到底是乘号还是除号
if (c == '*') {
d1 *= d2;
}else {
d1 /= d2;
}
//将运算结果,放回数字集合的i的位置
nums.add(i, d1);
//为了避免i+1位置的乘除号被跳过。因为取出一个符号之后,后面的符号就会往前移动。
i --;
}
}
//for循环结束后,表示乘除法做完了,只剩下加减法,opts里面只有+-号
//后加减,一直到所有运算符都被移除
while(!opts.isEmpty()){
//从运算符集合的0的位置取出运算符
char opt = opts.remove(0);
//从数字集合的0的位置取出第一个数
double d1 = nums.remove(0);
//从数字集合的0的位置取出第二个数
double d2 = nums.remove(0);
if (opt == '+') {
d1 += d2;
}else {
d1 -= d2;
}
//将运算结果放回到数字集合的0的位置
nums.add(0, d1);
}
//运算结束后,数字集合0的位置的值就是运算结果。
result = nums.get(0);
//后加减
return result;
}
/**
* 提取运算符集合
* @param exp
* @return
*/
private static List<Character> getOpts(String exp) {
//定义一个集合来,存储运算符
List<Character> opts = new ArrayList<>();
//用来分隔字符串的api
StringTokenizer sTokenizer = new StringTokenizer(exp, "0123456789.@");
while(sTokenizer.hasMoreElements()){
String strs = sTokenizer.nextElement().toString();
opts.add(strs.charAt(0));
}
return opts;
}
/**
* 提取数字集合
* @param exp
* @return
*/
private static List<Double> getNums(String exp) {
//定义一个集合来存储数字
List<Double> nums = new ArrayList<>();
StringTokenizer sTokenizer = new StringTokenizer(exp, "+-*/");
while (sTokenizer.hasMoreElements()) {
String str = sTokenizer.nextElement().toString();
//判断str中是否包含@,如果包含,则要将@符号转换成-。
if (str.charAt(0) == '@') {
//将@符号转换成-号
str = "-" + str.substring(1);
}
//String要转换成Double类型
double d = Double.parseDouble(str);
nums.add(d);
}
return nums;
}
/**
* 将负号转换成@符号
* @param exp
* @return
*/
private static String fu2At(String exp) {
//先遍历字符串
for (int i = 0; i < exp.length(); i++) {
char c = exp.charAt(i);
if (c == '-') {
//如果c是第零个
if (i == 0) {
//一定表示负号
exp = "@" + exp.substring(1);
}else {
//如果不是0的位置
//判断c前面的一个字符是否是运算符
char prev = exp.charAt(i - 1);
if (prev == '+' || prev == '-' || prev == '*' || prev == '/') {
//说明c一定是表示负号
exp = exp.substring(0, i) + "@" + exp.substring(i + 1);
}
}
}
}
return exp;
}
/*上述是基本小括号的运算,
下面2个方法是对中括号,大括号的增加*/
private static Double dkuohao(String exp) {
int indexStart = exp.lastIndexOf('{');
if(indexStart >= 0){
int indexEnd = exp.indexOf('}',indexStart);
String temp = exp.substring(indexStart+1,indexEnd);
double d = zkuohao(temp);
exp = exp.substring(0,indexStart)+d+exp.substring(indexEnd+1);
return dkuohao(exp);
}else{
return zkuohao(exp);
}
}
private static Double zkuohao(String exp) {
int indexStart = exp.lastIndexOf('[');
if(indexStart >= 0){
int indexEnd = exp.indexOf(']',indexStart);
String temp = exp.substring(indexStart+1,indexEnd);
double d = calcKuohao(temp);
exp = exp.substring(0,indexStart)+d+exp.substring(indexEnd+1);
System.out.println(exp);
return zkuohao(exp);
}else{
return calcKuohao(exp);
}
}
}