`
graying
  • 浏览: 27494 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

为了替换项目里面的bsh-core,自己写了个eval

    博客分类:
  • Java
阅读更多
自己的game需要代码尽量小,但是bsh-core就占了200多k,很不爽,想想自己的代码中,需要用到bsh的地方就是计算java中带 +-*/%()等的计算公式,干脆,自己来写一个吧

除了异常比较难控制,基本都能实现了,代码量一下从291k下降到了11k



抛砖引玉,代码写的不是很pattern,只是希望能找到一些同好的朋友,引起一些共鸣,需要上一个game里面的高级算法,请联系我


主程序分4步,分别有去括号和计算运算符,计算运算符还分优先级,请注意注释部分



	/*******************************************************************************/
	public static final String ERROR_POWER = "can't use 1 ^ X = 1 this exp!";
	public static final String ERROR_START = "can't start with symb!";
	public static final String ERROR_EMPTY_EXP = "empty exp!";
	public static final String ERROR_EMPTY_VAL = "empty exp value!";
	public static final String ERROR_EXPERT = "error expert epx!";
	public static final String ERROR_LEFT_BRACKET = "no match \"( \"";
	public static final String ERROR_MOD = "can't use X mod "
			+ Constant.ERROR_MOD + " this exp!";
	public static final String ERROR_DIV_ZERO = "can't divide by zero!";
	public static final String ERROR_INFINITY = "Infinity!";
	public static final String ERROR_UNKNOWN = "unknow expression error occured!";

	// public static final String Utility65="no expert exp..*&^*#%(@";

	private static class ExpressionException extends RuntimeException {
		public ExpressionException(String message) {
			super(message);
		}
	}

	/**
	 * 用BSH计算表达式的运行结果,用于用户计算
	 */
	public static String calculateExpressionValue(String exp)
			throws ExpressionException {
		String temp;
		// 1. format
		temp = format(exp);
		if (Constant.DEBUG)
			System.out.println("format: from: " + exp + ", to: " + temp);
		exp = temp;
		// 2. get ride of "(" and ")".
		while (exp.indexOf(") ") > 0) {
			int end = exp.indexOf(") ");
			int start = exp.substring(0, end).lastIndexOf("( ") + 2;
			if (start < 2)
				throw new ExpressionException(ERROR_LEFT_BRACKET);
			String middleExp = exp.substring(start, end);
			temp = calculateExpressionValue(middleExp);
			// TODO bug: 8/(1/(11-8))
			if (Constant.DEBUG)
				System.out.println("trans: \"" + middleExp + "\" to \"" + temp
						+ "\"");
			exp = exp.substring(0, start - 2) + temp + " "
					+ exp.substring(end + 2);
		}

		// 3. calc the ^,l,√,expertExp value
		while (indexofExpert(exp) >= 0) {
			// the expert symb start
			int i = indexofExpert(exp);
			if (Constant.DEBUG)
				System.out.println("exp=" + exp + ",i=" + i);
			if (exp.substring(i, i + 1).equals("l")) {
				if (Constant.DEBUG)
					System.out.println("1");
				// if: log 2 8 -> 2 log 8
				// ... + log 2 8
				if ((i == 0 || !NumberUtils.isNumber(wordBefore(exp, i)))
						&& NumberUtils.isNumber(wordAfter(exp, i, 2))) {
					if (Constant.DEBUG)
						System.out.println("2");
					String a = wordAfter(exp, i);
					a = exp.substring(0, i) + a + " " + "l" + " "
							+ exp.substring(i + 3 + a.length());
					if (Constant.DEBUG)
						System.out.println("trans exp from: " + exp + ", to: "
								+ a);
					exp = a;
					i = indexofExpert(exp);
				}
			}
			if (exp.substring(i, i + 1).equals("^")) {
				if (!Constant.eliminatePower
						&& Float.parseFloat(wordBefore(exp, i)) == 1) {
					throw new ExpressionException(ERROR_POWER);
				}
			}
			if (exp.substring(i, i + 1).equals("%")) {
				if (Float.parseFloat(wordAfter(exp, i)) < Constant.MIN_MOD) {
					throw new ExpressionException(ERROR_MOD);
				}
			}
			if (Constant.DEBUG)
				System.out.println("exp=" + exp + ",i=" + i);
			if (i < 2)
				throw new ExpressionException(ERROR_START);
			// get the num before symb.
			int start = exp.substring(0, i - 1).lastIndexOf(" ") + 1;
			// TODO symb length
			int t = exp.substring(i + 1 + 1).indexOf(" ");
			int end = i + 2 + (t < 0 ? exp.substring(i + 2).length() : t);
			String expertStr = exp.substring(start, end);
			// throw
			temp = evalExpert(expertStr);
			if (Constant.DEBUG)
				System.out.println("expert: \"" + expertStr + "\" to \"" + temp
						+ "\"");
			exp = exp.substring(0, start) + temp + " "
					+ (t < 0 ? "" : exp.substring(end + 1));
		}
		// 4. simple eval
		String[] doubleExps = exp.split(" ");
		for (int i = 0; i < doubleExps.length; i++) {
			String e = doubleExps[i];
			if (e.length() > 0 && NumberUtils.isDigits(e) && e.indexOf('.') < 0) {
				doubleExps[i] += ".0";// trans to double
			}
		}
		exp = "";
		for (String e : doubleExps) {
			exp += e + " ";
		}
		if (Constant.DEBUG)
			System.out.println("double: trans to: " + exp);
		return evalBase(exp);

	}

	private static String evalBase(String exp) throws ExpressionException {
		int i = indexofMulDiv(exp);
		while (i > 0) {
			String sym = exp.substring(i, i + 1);
			String num1 = wordBefore(exp, i);
			String num2 = wordAfter(exp, i);

			int start = exp.substring(0, i - 1).lastIndexOf(" ") + 1;
			// TODO symb length
			int t = exp.substring(i + 1 + 1).indexOf(" ");
			int end = i + 2 + (t < 0 ? exp.substring(i + 2).length() : t);
			if (Constant.DEBUG)
				System.out.println("in evalBase: " + num1 + sym + num2);
			String temp = evalBaseMath(num1, sym, num2);
			if (Constant.DEBUG)
				System.out.println("in evalBase: answer:" + temp);
			exp = exp.substring(0, start) + temp + " "
					+ (t < 0 ? "" : exp.substring(end + 1));
			if (Constant.DEBUG)
				System.out.println("in evalBase: exp trans to:" + exp);
			i = indexofMulDiv(exp);
		}

		while (exp.indexOf(" ") != exp.lastIndexOf(" ")) {
			int j = exp.indexOf(" ") + 1;
			if (Constant.DEBUG)
				System.out.println("in evalBase:2 exp=" + exp + ",j=" + j);
			String num1 = exp.substring(0, j - 1);
			String sym = exp.substring(j, j + 1);
			String num2 = wordAfter(exp, j);
			if (Constant.DEBUG)
				System.out.println("in evalBase:2 " + num1 + sym + num2);
			exp = evalBaseMath(num1, sym, num2)
					+ exp.substring(j + 1 + 1 + num2.length());
			if (Constant.DEBUG)
				System.out.println("in evalBase:2 exp trans to:" + exp);
		}
		return exp.substring(0, exp.length() - 1);

	}

	private static String evalBaseMath(String num1, String exp, String num2)
			throws ExpressionException {
		float num_1 = Float.parseFloat(num1);
		float num_2 = Float.parseFloat(num2);
		if (exp.equals("+")) {
			return String.valueOf(num_1 + num_2);
		} else if (exp.equals("-")) {
			return String.valueOf(num_1 - num_2);
		} else if (exp.equals("*")) {
			return String.valueOf(num_1 * num_2);
		} else if (exp.equals("/")) {
			float x = num_1 / num_2;
			if (Float.isInfinite(x) || num_2 == 0) {
				throw new ExpressionException(ERROR_DIV_ZERO);
			}
			return String.valueOf(x);
		} else {
			throw new ExpressionException(ERROR_UNKNOWN);
		}
	}

	// private static String evalBase_x(String exp) throws ExpressionException {
	// try {
	// if (exp == null || exp.trim().equals("")) {
	// throw new ExpressionException(ERROR_EMPTY_EXP);
	// }
	// Object obj = i.evalBase(exp);
	// if (obj == null) {
	// throw new ExpressionException(ERROR_EMPTY_VAL);
	// }
	// String temp = obj.toString();
	// if (Constant.DEBUG)
	// System.out.println("trans exp: \"" + exp + "\" to \"" + temp
	// + "\"");
	// return temp;
	// } catch (EvalError e) {
	// e.printStackTrace();
	// throw new ExpressionException(ERROR_UNKNOWN);
	// }
	// }

	private static String evalExpert(String expertStr)
			throws ExpressionException {
		String[] eps = expertStr.split(" ");
		double num1 = Double.parseDouble(eps[0]);
		double num2 = Double.parseDouble(eps[2]);
		if (eps.length != 3) {
			throw new ExpressionException(ERROR_EXPERT);
		}
		if (eps[1].equals("^")) {
			return String.valueOf(Math.pow(num1, num2));
		} else if (eps[1].equals("√")) {
			double x = 1.0 / num1;
			if (Double.isInfinite(x) || num1 == 0) {
				throw new ExpressionException(ERROR_INFINITY);
			}
			return String.valueOf(Math.pow(num2, x));
		} else if (eps[1].equals("l")) {
			double x = Math.log10(num1);
			if (num1 == 0 || x == 0) {
				throw new ExpressionException(ERROR_INFINITY);
			}
			x = Math.log10(num2) / x;
			if (Double.isInfinite(x)) {
				throw new ExpressionException(ERROR_INFINITY);
			}
			return String.valueOf(x);
		} else if (eps[1].equals("%")) {
			if (num2 == 0) {
				throw new ExpressionException(ERROR_INFINITY);
			}
			return String.valueOf(num1 % num2);
		}
		return null;
	}

	private static int indexofMulDiv(String exp) {
		int i = exp.indexOf("*" + " ");
		int j = exp.indexOf("/" + " ");
		return i == -1 ? j : (j == -1 ? i : j);
	}

	/**
	 * @return minimal not -1 value
	 */
	private static int indexofExpert(String exp) {
		int i = exp.indexOf("^" + " ");
		int j = exp.indexOf("√" + " ");
		int k = exp.indexOf("l" + " ");
		int l = exp.indexOf("%" + " ");
		int r = -1;
		if (i != -1)
			r = i;
		if (j != -1)
			r = r == -1 ? j : (r < j ? r : j);
		if (k != -1)
			r = r == -1 ? k : (r < k ? r : k);
		if (l != -1)
			r = r == -1 ? l : (r < l ? r : l);
		return r;
	}

	private static String format(String exp) {
		for (Entry<String, String> entry : Constant.expressionFormats
				.entrySet()) {
			exp = exp.replaceAll(entry.getKey() + " ", entry.getValue() + " ");
		}
		return exp;
	}

	private static String wordAfter(String exp, int idx) {
		return wordAfter(exp, idx, 1);
	}

	private static String wordAfter(String exp, int idx, int count) {
		if (idx >= exp.length())
			return null;
		exp = exp.substring(idx);
		if (exp.length() < 1 + count * 2)
			return null;// is last
		for (int i = 0; i < count; i++)
			exp = exp.substring(exp.indexOf(" ") + 1);
		return exp.substring(0, exp.indexOf(" "));
	}

	private static String wordBefore(String exp, int idx) {
		if (idx < 2)
			return null;
		exp = exp.substring(0, idx - 1);// minus 1 space
		return exp.substring(exp.lastIndexOf(" ") + 1);
	}

	public static void main(String[] args) {
		String answer = Utility.calculateExpressionValue("( 2 + 9 ) log 0 ");
		// if (Constant.DEBUG)
		System.out.println(answer);
	}



补充一句,比bsh做得多的地方是能计算 ^, √, log等特殊数学运算符,当然实现部分是用Math做得。

0
0
分享到:
评论

相关推荐

    bsh-2.0b6-API文档-中英对照版.zip

    赠送jar包:bsh-2.0b6.jar; 赠送原API文档:bsh-2.0b6-javadoc.jar; 赠送源代码:bsh-2.0b6-sources.jar; 赠送Maven依赖信息文件:bsh-2.0b6.pom; 包含翻译后的API文档:bsh-2.0b6-javadoc-API文档-中文(简体)-...

    bsh-1.3.0.jar

    bsh-1.3.0.jar;bsh-1.3.0.jar;bsh-1.3.0.jar;bsh-1.3.0.jar;bsh-1.3.0.jar

    bsh-2.0b4.jar

    大家想没有把java做一门脚本语言来执行? BeanShell就是这样一的个工具。

    bsh-2.0b6.jar

    bsh-2.0b6.jar

    bsh-core.jar

    jar包,亲测可用

    反射jar(bsh-core-2.0b4.jar)

    可以通过这个jar进行使用反射,完成项目的一些框架的开发

    bsh-core-2.0b4.jar

    直接对输入的公式进行计算

    Java计算数学表达式的结果的jar包(bsh-2.0b4.jar)

    Java计算数学表达式的结果主要依赖于像bsh(BeanShell)这样的库,BeanShell是一个小型、开源的Java脚本环境,它可以动态执行Java代码并提供一个交互式的解释器。在这个场景中,`bsh-2.0b4.jar` 是BeanShell的一个...

    bsh-2.0.jar

    jar包,亲测可用

    RTL8822BSH-VQ-CG+DataSheet_v0.1r13_20171114.pdf

    根据提供的文件信息,这份数据手册属于Realtek Semiconductor Corp的RTL8822BSH-VQ-CG产品,这是一款集成了蓝牙智能就绪控制器的单芯片802.11ac/a/b/g/n 2T2R WLAN设备,具有SDIO/HS-UART混合接口功能。以下将详细...

    bsh-2.0b6-API文档-中文版.zip

    赠送jar包:bsh-2.0b6.jar; 赠送原API文档:bsh-2.0b6-javadoc.jar; 赠送源代码:bsh-2.0b6-sources.jar; 赠送Maven依赖信息文件:bsh-2.0b6.pom; 包含翻译后的API文档:bsh-2.0b6-javadoc-API文档-中文(简体)版...

    plexus-bsh-factory-1.0-0.14.a7.el7.x64-86.rpm.tar.gz

    PLEXUS-BSH-FACTORY是Plexus项目中的一个组件,它主要负责管理Apache Maven插件的生命周期。它使用BeanShell脚本来定义和执行插件任务。BeanShell是一种小型的、动态的语言,可以将Java对象作为普通变量进行处理。...

    plexus-bsh-factory-javadoc-1.0-0.14.a7.el7.x64-86.rpm.tar.gz

    plexus-bsh-factory-javadoc-1.0-0.14.a7.el7.x64-86.rpm.tar.gz文件是一个Linux系统的软件包压缩文件,包含了plexus-bsh-factory-javadoc-1.0-0.14.a7.el7.x64-86版本的RPM(RPM包管理器)文件及其依赖。这个压缩包...

    java 类库bsh-1.2

    java的工具类库, 运行过程中可执行嵌入java代码

    bsh-utils-1.3.0-29.el7.x64-86.rpm.tar.gz

    bsh-utils-1.3.0-29.el7.x64-86.rpm.tar.gz是一个包含多个rpm安装包的压缩文件。这些rpm包是Red Hat Linux企业版7(RHEL 7)的软件包,其中包含了BeanShell实用工具(bsh-utils)的1.3.0版本,以及该软件所依赖的...

    bsh-demo-1.3.0-29.el7.x64-86.rpm.tar.gz

    标题中的“bsh-demo-1.3.0-29.el7.x64-86.rpm.tar.gz”指向一个包含了bsh-demo-1.3.0-29.el7.x64-86版本的RPM包的压缩文件。RPM即“RPM包管理器”,是Linux系统中用于安装、卸载、查询和管理软件包的工具。它是一种...

    bsh-1.3.0-29.el7.x64-86.rpm.tar.gz

    1、文件内容:bsh-1.3.0-29.el7.rpm以及相关依赖 2、文件形式:tar.gz压缩包 3、安装指令: #Step1、解压 tar -zxvf /mnt/data/output/bsh-1.3.0-29.el7.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *...

    bsh.jar,jcr-1.0.jar,jbpm-identity.jar,jbpm-jpdl.jar

    1. **bsh.jar**:这是一个BeanShell库的JAR文件,BeanShell是一个轻量级的Java脚本环境。它允许开发者在运行时动态地执行Java代码,这对于测试、调试或者在应用程序中实现脚本功能非常有用。在JBPM中,BeanShell被...

Global site tag (gtag.js) - Google Analytics