最簡單卻又極具擴展性的Java表達式引擎,自創編程語言必備

這個表達式引擎只有短短的100多行,卻能實現包括加減乘除、括號優先級在內的運算,能夠在「處理表達式」函數中自行擴展想要處理的算法。這裏面算法的難點主要在於如何實如今多級括號存在的狀況下,能取出最外層的一對括號,「成對處理」函數能夠普遍的應用在爬蟲、數據抓取的軟件中。java


很少說,先上源碼算法

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