解析一般数学算式,实现简单的带括号的加减乘除运算。
先从我们人的角度,考虑平时在计算一个式子的思路,任意假设一个的数学表达式-3.5*(4.5-(4+(-1-1/2)))
简单总结,即**先去括号至无括号,再去乘除至无乘除,最后去加减至无加减**,以此思路编写程序如下,结合注释分析具体步骤:
环境:
先写一个最基本的两位数四则运算方法,比较简单,没有写注释:
public static double doubleCal(double a1, double a2, char operator) throws Exception {
switch (operator) {
case '+':
return a1 + a2;
case '-':
return a1 - a2;
case '*':
return a1 * a2;
case '/':
return a1 / a2;
default:
break;
}
throw new Exception("illegal operator!");
}
解析运算表达式的方法:
public static String getResult(String str) throws NumberFormatException, Exception {
//处理一下计算过程中出现的--情况,首位--直接去掉,中间--变为+
str = str.startsWith("--") ? str.substring(2) : str;
str = str.replaceAll("--", "+");
str = str.replaceAll("\\+-", "-");
System.out.println("新表达式:"+str);
if (str.matches("-{0,1}[0-9]+([.][0-9]+){0,1}"))//不存在运算符了,即递归结束,这里的正则为匹配所有的正负整数及小数
return str;
/*表示每次递归计算完一步后的表达式*/
String newExpr = null;
// 第一步:去括号至无括号
if (str.contains("(")) {
/*最后一个左括号的索引值*/
int lIndex = str.lastIndexOf("(");
/*该左括号对应的右括号的索引*/
int rIndex = str.indexOf(")", lIndex);
/*括号中的字表达式*/
String subExpr = str.substring(lIndex + 1, rIndex);
System.out.println("准备括号:("+subExpr+")");
newExpr = str.substring(0, lIndex) + getResult(subExpr) //调用本身,计算括号中表达式结果
+ str.substring(rIndex + 1);
return getResult(newExpr);
}
// 第二步:去乘除至无乘除
if (str.contains("*") || str.contains("/")) {
/*该正则表示匹配一个乘除运算,如1.2*3 1.2/3 1.2*-2 等*/
Pattern p = Pattern.compile("[0-9]+([.][0-9]+){0,1}[*/]-{0,1}[0-9]+([.][0-9]+){0,1}");
Matcher m = p.matcher(str);
if (m.find()) {
/*第一个乘除表达式*/
String temp = m.group();
System.out.println("计算乘除:"+temp);
String[] a = temp.split("[*/]");
newExpr = str.substring(0, m.start())
+ doubleCal(Double.valueOf(a[0]), Double.valueOf(a[1]), temp.charAt(a[0].length()))
+ str.substring(m.end());
}
return getResult(newExpr);
}
// 第三步:去加减至无加减
if (str.contains("+") || str.contains("-")) {
/*该正则表示匹配一个乘除运算,如1.2+3 1.2-3 1.2--2 1.2+-2等*/
Pattern p = Pattern.compile("-{0,1}[0-9]+([.][0-9]+){0,1}[+-][0-9]+([.][0-9]+){0,1}");
Matcher m = p.matcher(str);
if (m.find()) {
/*第一个加减表达式*/
String temp = m.group();
System.out.println("计算加减:"+temp);
String[] a = temp.split("\\b[+-]", 2);
newExpr = str.substring(0, m.start())
+ doubleCal(Double.valueOf(a[0]), Double.valueOf(a[1]), temp.charAt(a[0].length()))
+ str.substring(m.end());
}
return getResult(newExpr);
}
throw new Exception("Calculation error");
}
主方法:
public static void main(String[] args) throws Exception {
String str = "-3.5*(4.5-(4+(-1-1/2)))";
System.out.println("开始计算表达式:"+str);
System.out.println("结果为:"+getResult(str));
}
再来个简略版的
public class test {
static boolean isNumber(String str) {//判断表达式是不是只有一个数字
for(int i=0;i
这种方法以我们平时计算的思路入手,思路较为清晰,代码简略,但直接遍历拼接字符串,代码并不好读,多次递归效率也必然较低。引入第二种思路,采用java的容器进一步优化算法及代码。