公式顺序解析之加减乘除的执行顺序
在上文:java根据Stack栈实现公式解析和自定义函数(二)的结尾有三个问题
1. 加减乘除只支持两位
2. 前缀的加减乘除还不支持
3. 在末尾加减乘除会遇到数组下标越界的问题
博主的思路已经有些混乱了,感觉不太对,所以我们先来把加减乘除的解析计算写一下,自己也捋捋思路,有经验的大佬请指导一下这个菜鸟博主。
思路:
1. 将乘除括号起来以做到先乘除后加减的顺序,如1+2*4/5处理完应该是1+((2*4)/5)
2. 总共分成两步,公式解析为一步,解析成上面的示例格式,再使用栈的先进后出的特性进行层层计算,主要部分在公式解析里面,如果有括号还要包整个括号,如果括号里面有乘除则需要再包起来,包的过程类似递归,这个以后可以考虑单独写个方法。
3. 计算方法,解析完公式就该进行计算,在我们上层处理完公式后其实每层括号只会有两个值,逻辑跟之前的类似但不同,四个判断为:
前括号判断:一层判断的开始
数值判断:参数值的计数存入
加减乘除判断:运算符的存入
后括号的判断:本层的计算结束出栈所有括号、数值、运算符,将得到的结果存到参数值栈,外层循环和结果会用
加减乘除源代码
package com.example.demo.java;
import java.util.Stack;
/**
* @author Anzepeng
* @title: OrdinaryCalculate
* @projectName demo
* @description: 普通运算
* @date 2020/6/9 0009上午 11:39
*/
public class OrdinaryCalculate {
public static boolean judgeNumber(char s) {
if(s >= '0' && s <= '9')
return true;
return false;
}
public static boolean judgeChar(char s) {
if(s >= 'a' && s <= 'z' || s >= 'A' && s <= 'Z')
return true;
return false;
}
/**
* @description: 公式解析
* @param parm
* @return String
* @throws
* @author Anzepeng
* @date 2020/6/9 0009 下午 13:18
*/
public static String formulaParsing(String parm) {
// 运行符和数据分成两个数组
String[] o = new String[parm.length()];
String[] n = new String[parm.length()];
for (int i = 0; i < parm.length(); i++) {
if (parm.charAt(i) == '+' || parm.charAt(i) == '-' || parm.charAt(i) == '*' || parm.charAt(i) == '/' || parm.charAt(i) == '(' || parm.charAt(i) == ')') {
o[i] = String.valueOf(parm.charAt(i));
} else if (judgeNumber(parm.charAt(i))) {
n[i] = String.valueOf(parm.charAt(i));
}
}
// 写到一起运行符以%间隔以便后面解析
String formula = new String();
for (int i = 0; i < o.length; i++) {
if (o[i] != null) {
formula += "%" + o[i] + "%";
} else if (n[i] != null) {
formula += n[i];
}
}
// 使用栈存储
Stack stack = new Stack();
String[] formulas = formula.split("%");
String[] f = new String[formula.length()];
int fSum = 0;
// 去除多个% split产生的空数组位数
for (int i = 0; i < formulas.length; i++) {
if (formulas[i]!=null && !"".equals(formulas[i])){
f[fSum] = formulas[i];
fSum++;
}
}
formulas = f;
// 以实际有数据的位数作为循环最大值
for (int i = 0; i < fSum; i++) {
// 若为*或/时则进行括号相加其他直接累加
if ("*".equals(formulas[i]) ||"/".equals(formulas[i])) {
String a = (String) stack.pop();
// 验证上一位是否是括号,如果是理应括住整个括号,这里没有扩,需要判断之前的括号有多少位
if (")".equals(a)){
String setF = a;
// 前面的括号处理
int sz = stack.size();// 记录栈的长度,不能再for直接用,否则出栈循环数也会减少
int eN = 1;// 记录后括号几个,因为已经出过一个后括号所以从1开始
int sN = 0;// 记录前括号几个,入股两个值一样则停止
for (int z = 0; z < sz; z++){
String zs = (String) stack.pop();
if (")".equals(zs)){
eN++;
}else if ("(".equals(zs)){
sN++;
}
setF = zs + setF;
if (eN == sN){
break;
}
}
String b = new String();
if ("(".equals(formulas[i + 1])){
// 后面的括号处理
boolean bs = true;
int wi = 2;// 这是为了循环定义的值,因为确定i+1已经是(所以从i+2开始
int sW = 1;// 记录前括号几个,因为已经出过一个前括号所以从1开始
int eW = 0;// 记录后括号几个
String setW = "(";// 这里直接定义接受前括号以便上面两个int值不一样
while (bs){
// 这里没有校验括号内的*和/给加上括号
String ws = formulas[i+wi];
if ("(".equals(ws)){
sW++;
}else if (")".equals(ws)){
eW++;
}
setW = setW + ws;
if (sW == eW){
break;
}else{
wi++;
}
}
b = "(" + setF + formulas[i] + setW + ")";
stack.push(b);
i = i+(wi);
}else{
b = "(" + setF + formulas[i] + formulas[i + 1] + ")";
stack.push(b);
i++;
}
}else if("(".equals(formulas[i + 1])){
String b = new String();
if ("(".equals(formulas[i + 1])){
// 后面的括号处理
boolean bs = true;
int wi = 2;// 这是为了循环定义的值,因为确定i+1已经是(所以从i+2开始
int sW = 1;
int eW = 0;
String setW = "(";
while (bs){
String ws = formulas[i+wi];
if ("(".equals(ws)){
sW++;
}else if (")".equals(ws)){
eW++;
}
if("*".equals(ws) || "/".equals(ws)){
String beforeStr = formulas[i+wi-1];
setW = setW.substring(0,setW.length()-beforeStr.length());
String afterStr = formulas[i+wi+1];
setW = setW+"("+beforeStr+ws+afterStr+")";
wi+=2;
}else{
setW = setW + ws;
wi++;
}
if (sW == eW){
break;
}
}
b = "(" + a + formulas[i] + setW + ")";
stack.push(b);
i = i+(wi);
}else{
b = "(" + a + formulas[i] + formulas[i + 1] + ")";
stack.push(b);
i++;
}
} else{
String b = "(" + a + formulas[i] + formulas[i + 1] + ")";
stack.push(b);
i++;
}
} else {
stack.push(formulas[i]);
}
}
String starkStr = (String) stack.pop();
int z = stack.size();
for (int i = 0; i < z; i++) {
starkStr = stack.pop() + starkStr;
}
return starkStr;
}
public static Stack<String> operation = new Stack<String>(); //存放运算符
public static Stack<Character> bracket = new Stack<Character>(); //存放左括号
public static Stack<Integer> number = new Stack<Integer>(); //存放运算参数
public static Stack<Integer> count = new Stack<Integer>(); //存放运算符参数个数
public static int jia(int[] N) {
return N[0] + N[1];
}
public static int jian(int[] N) {
return N[0] - N[1];
}
public static int cheng(int[] N) {
return N[0] * N[1];
}
public static int chu(int[] N) {
return N[0] / N[1];
}
/**
* @description: 计算
* @param ${tags}
* @return void
* @throws
* @author Anzepeng
* @date 2020/6/9 0009 下午 13:20
*/
public static void calculate(String formula){
String temp = "";
for(int i = 0;i < formula.length();i++) {
if(formula.charAt(i) == '(') {
bracket.push(formula.charAt(i));
} else if(judgeNumber(formula.charAt(i))) {
temp = temp + formula.charAt(i);
i = i + 1;
while (judgeNumber(formula.charAt(i))) {
temp = temp + formula.charAt(i);
i++;
}
i = i - 1;
number.push(Integer.valueOf(temp));
if (count.size() > 0) {
count.push(count.pop() + 1); //此处用于计算当前栈顶运算符实际参数个数
} else {
count.push(0 + 1);
}
temp = "";
}else if(formula.charAt(i) == '+' || formula.charAt(i) == '-' || formula.charAt(i) == '*' || formula.charAt(i) == '/'){
operation.push(String.valueOf(formula.charAt(i)));
} else if(formula.charAt(i) == ')') { //此时要进行运算
bracket.pop(); //栈顶左括号出栈
String tempOpera = operation.pop();
int end = number.pop();// 因为先进后出的特性,所以后值先出
int send = number.pop();// 前值后出
int[] N = {send,end};
int result = 0;
if(tempOpera.equals("+"))
result = jia(N);
else if(tempOpera.equals("-"))
result = jian(N);
else if(tempOpera.equals("*"))
result = cheng(N);
else if(tempOpera.equals("/"))
result = chu(N);
number.push(result);
}
}
}
public static void main(String[] args){
String formula = "4+(7-24*10)*91*(40/17+1)";
String formulaParsing = "("+formulaParsing(formula)+")";
System.out.println(formulaParsing);
calculate(formulaParsing);
System.out.println(number.pop());
}
}