这个表达式引擎只有短短的100多行,却能实现包括加减乘除、括号优先级在内的运算,可以在“处理表达式”函数中自行扩展想要处理的算法。这里面算法的难点主要在于如何实现在多级括号存在的情况下,能取出最外层的一对括号,“成对处理”函数可以广泛的应用在爬虫、数据抓取的软件中。
不多说,先上源码
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Calculate {
private Hashtable<String, Object> 堆栈值 = new Hashtable<>();
private int 表达式游标 = 0;
public static List<String> 成对处理(String code, String start, String end) {
List<String> subResult = new ArrayList<>();
String temp = "";
String nextLevelCode = "";
int level = 0;
for (char codeChar : code.toCharArray()) {
temp += codeChar;
if (temp.endsWith(end)) {
level--;
if (level == 0) {
subResult.add(nextLevelCode.toString());
nextLevelCode = "";
}
}
if (level != 0) {
nextLevelCode += codeChar;
}
if (temp.endsWith(start)) {
level++;
}
}
return subResult;
}
public static List<String> 前置处理(String code, String front) {
front = front.replace("+", "\\+").replace("-", "\\-");
return getMatchList(code, front + "[_a-zA-Z\\u4E00-\\u9FA5]+[0-9]*");
}
public static List<String> 后置处理(String code, String back) {
back = back.replace("+", "\\+").replace("-", "\\-");
return getMatchList(code, "[_a-zA-Z\\u4E00-\\u9FA5]+[0-9]*" + back);
}
public static List<String> 运算处理(String code, String calc) {
calc = calc.replace("+", "\\+").replace("*", "\\*").replace("-", "\\-");
return getMatchList(code,
"[_a-zA-Z0-9\\u4E00-\\u9FA5]+[\\.]*[0-9]*" + calc + "[_a-zA-Z\\u4E00-\\u9FA5]*[0-9]*[\\.]*[0-9]*");
}
public Object 处理表达式(String 表达式) throws Exception {
List<String> 子表达式列表 = new ArrayList();
// 先运算括号中的内容
子表达式列表 = 成对处理(表达式, "(", ")");
if (子表达式列表.size() != 0) {
for (String 子表达式 : 子表达式列表) {
Object 子表达式值 = 处理表达式(子表达式);
String 游标键 = "_V" + (表达式游标++);
堆栈值.put(游标键, 子表达式值);
表达式 = 表达式.replace("(" + 子表达式 + ")", 游标键);
}
return 处理表达式(表达式);
}
表达式 = 表达式.replace(" ", "");
// 运算乘法
if (表达式.contains("*"))
子表达式列表 = 运算处理(表达式, "*");
if (子表达式列表.size() != 0) {
for (String 子表达式 : 子表达式列表) {
String 乘数 = 子表达式.split("\\*")[0];
String 被乘数 = 子表达式.split("\\*")[1];
if (乘数.startsWith("_V"))
乘数 = 堆栈值.get(乘数).toString();
if (被乘数.startsWith("_V"))
被乘数 = 堆栈值.get(被乘数).toString();
Object 子表达式值 = Double.parseDouble(乘数) * Double.parseDouble(被乘数);
String 游标键 = "_V" + (表达式游标++);
堆栈值.put(游标键, 子表达式值);
表达式 = 表达式.replace(子表达式, 游标键);
}
return 处理表达式(表达式);
}
// 运算除法
if (表达式.contains("/"))
子表达式列表 = 运算处理(表达式, "/");
if (子表达式列表.size() != 0) {
for (String 子表达式 : 子表达式列表) {
String 乘数 = 子表达式.split("/")[0];
String 被乘数 = 子表达式.split("/")[1];
if (乘数.startsWith("_V"))
乘数 = 堆栈值.get(乘数).toString();
if (被乘数.startsWith("_V"))
被乘数 = 堆栈值.get(被乘数).toString();
Object 子表达式值 = Double.parseDouble(乘数) / Double.parseDouble(被乘数);
String 游标键 = "_V" + (表达式游标++);
堆栈值.put(游标键, 子表达式值);
表达式 = 表达式.replace(子表达式, 游标键);
}
return 处理表达式(表达式);
}
// 运算加法
if (表达式.contains("+"))
子表达式列表 = 运算处理(表达式, "+");
if (子表达式列表.size() != 0) {
for (String 子表达式 : 子表达式列表) {
String 乘数 = 子表达式.split("\\+")[0];
String 被乘数 = 子表达式.split("\\+")[1];
if (乘数.startsWith("_V"))
乘数 = 堆栈值.get(乘数).toString();
if (被乘数.startsWith("_V"))
被乘数 = 堆栈值.get(被乘数).toString();
Object 子表达式值 = Double.parseDouble(乘数) + Double.parseDouble(被乘数);
String 游标键 = "_V" + (表达式游标++);
堆栈值.put(游标键, 子表达式值);
表达式 = 表达式.replace(子表达式, 游标键);
}
return 处理表达式(表达式);
}
// 运算加法
if (表达式.contains("-"))
子表达式列表 = 运算处理(表达式, "-");
if (子表达式列表.size() != 0) {
for (String 子表达式 : 子表达式列表) {
String 乘数 = 子表达式.split("\\-")[0];
String 被乘数 = 子表达式.split("\\-")[1];
if (乘数.startsWith("_V"))
乘数 = 堆栈值.get(乘数).toString();
if (被乘数.startsWith("_V"))
被乘数 = 堆栈值.get(被乘数).toString();
Object 子表达式值 = Double.parseDouble(乘数) - Double.parseDouble(被乘数);
String 游标键 = "_V" + (表达式游标++);
堆栈值.put(游标键, 子表达式值);
表达式 = 表达式.replace(子表达式, 游标键);
}
return 处理表达式(表达式);
}
// 如果到最后是一个变量,则直接返回变量值
if (表达式.matches("_V[0-9]+")) {
return 堆栈值.get(表达式).toString();
}
throw new Exception("无法处理的表达式:" + 表达式);
}
public static List<String> getMatchList(String managers, String match) {
List<String> ls = new ArrayList<String>();
Pattern pattern = Pattern.compile(match);
Matcher matcher = pattern.matcher(managers);
while (matcher.find())
ls.add(matcher.group());
return ls;
}
}
测试程序:
public class Test {
public static void main(String args[]) throws Exception{
String 表达式="100.25+ (100 /( 25+ 12.5*2))+50/(23+(1+1))";
System.out.println(new Calculate().处理表达式(表达式));
}
}
输出结果:104.25