`

在Java中计算四则运算表达式字符串的值

    博客分类:
  • Java
阅读更多

在项目中有个需求,需要动态的计算一个四则运算表达式的结果,在JS中做这个非常方便,用eval表达式就搞定了,但在Java语言里就没那么容易了,上网搜了一下没有找到满意的,小弟不才,网上很多代码看不明白,唉,无奈下,自己利用Java中的正则表达式做了一个简单的包括了加减乘除及小括号的计算方法。因为时间仓促,为了赶进度,没仔细进行验证,现在贴出来,请大家拍拍砖,有什么好的解决方法,或考虑到效率问题,还请多多指教。

套话少说了,我的程序的思路是:

1、首先循环获取取最小单位的小括号表达式进行加减乘除计算,直到表达式中不包含小括号为止

2、然后对每个不含括号的表达式,在按顺序执行乘除法,直到没有乘除法表达式

3、最后计算所有的加减表达式,执行的顺序就是按顺序执行了

    a)对于负数运算,首先将其负号去除,同时将相应运算单元的加减号转换,然后再进行运算

import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 报表工具类
 * @author ZYWANG 2009-7-28
 */
public final class ReportUtil {
	/**
	 * 格式化日期
	 * @param obj 日期对象
	 * @param format 格式化字符串
	 * @return
	 * @author ZYWANG 2009-8-26
	 */
	public static String formatDate(Object obj, String format) {
		if (obj == null)
			return "";

		String s = String.valueOf(obj);
		if (format == null || "".equals(format.trim())) {
			format = "yyyy-MM-dd";
		}
		try {
			SimpleDateFormat dateFormat = new SimpleDateFormat(format);
			s = dateFormat.format(obj);
		} catch (Exception e) {
		}
		return s;
	}

	/**
	 * 格式化数字
	 * @param obj 数字对象
	 * @param format 格式化字符串
	 * @return
	 * @author ZYWANG 2009-8-26
	 */
	public static String formatNumber(Object obj, String format) {
		if (obj == null)
			return "";

		String s = String.valueOf(obj);
		if (format == null || "".equals(format.trim())) {
			format = "#.00";
		}
		try {
			if (obj instanceof Double || obj instanceof Float) {
				if (format.contains("%")) {
					NumberFormat numberFormat = NumberFormat.getPercentInstance();
					s = numberFormat.format(obj);
				} else {
					DecimalFormat decimalFormat = new DecimalFormat(format);
					s = decimalFormat.format(obj);
				}
			} else {
				NumberFormat numberFormat = NumberFormat.getInstance();
				s = numberFormat.format(obj);
			}
		} catch (Exception e) {
		}
		return s;
	}

	/**
	 * 计算字符串四则运算表达式
	 * @param string
	 * @return
	 * @author ZYWANG 2009-8-31
	 */
	public static String computeString(String string) {
		String regexCheck = "[\\(\\)\\d\\+\\-\\*/\\.]*";// 是否是合法的表达式

		if (!Pattern.matches(regexCheck, string))
			return string;

		Matcher matcher = null;
		String temp = "";
		int index = -1;
		String regex = "\\([\\d\\.\\+\\-\\*/]+\\)";// 提取括号表达式
		string = string.replaceAll("\\s", "");// 去除空格
		try {
			Pattern pattern = Pattern.compile(regex);
			// 循环计算所有括号里的表达式
			while (pattern.matcher(string).find()) {
				matcher = pattern.matcher(string);
				while (matcher.find()) {
					temp = matcher.group();
					index = string.indexOf(temp);
					string = string.substring(0, index)
							+ computeStirngNoBracket(temp)
							+ string.substring(index + temp.length());
				}
			}
			// 最后计算总的表达式结果
			string = computeStirngNoBracket(string);
		} catch (NumberFormatException e) {
			return e.getMessage();
		}
		return string;
	}

	/**
	 * 计算不包含括号的表达式
	 * @param string
	 * @return
	 * @author ZYWANG 2009-8-31
	 */
	private static String computeStirngNoBracket(String string) {
		string = string.replaceAll("(^\\()|(\\)$)", "");
		String regexMultiAndDivision = "[\\d\\.]+(\\*|\\/)[\\d\\.]+";
		String regexAdditionAndSubtraction = "(^\\-)?[\\d\\.]+(\\+|\\-)[\\d\\.]+";

		String temp = "";
		int index = -1;

		// 解析乘除法
		Pattern pattern = Pattern.compile(regexMultiAndDivision);
		Matcher matcher = null;
		while (pattern.matcher(string).find()) {
			matcher = pattern.matcher(string);
			if (matcher.find()) {
				temp = matcher.group();
				index = string.indexOf(temp);
				string = string.substring(0, index) + doMultiAndDivision(temp)
						+ string.substring(index + temp.length());
			}
		}

		// 解析加减法
		pattern = Pattern.compile(regexAdditionAndSubtraction);
		while (pattern.matcher(string).find()) {
			matcher = pattern.matcher(string);
			if (matcher.find()) {
				temp = matcher.group();
				index = string.indexOf(temp);
				if (temp.startsWith("-")) {
					string = string.substring(0, index)
							+ doNegativeOperation(temp)
							+ string.substring(index + temp.length());
				} else {
					string = string.substring(0, index)
							+ doAdditionAndSubtraction(temp)
							+ string.substring(index + temp.length());
				}
			}
		}

		return string;
	}

	/**
	 * 执行乘除法
	 * @param string
	 * @return
	 * @author ZYWANG 2009-8-31
	 */
	private static String doMultiAndDivision(String string) {
		String value = "";
		double d1 = 0;
		double d2 = 0;
		String[] temp = null;
		if (string.contains("*")) {
			temp = string.split("\\*");
		} else {
			temp = string.split("/");
		}

		if (temp.length < 2)
			return string;

		d1 = Double.valueOf(temp[0]);
		d2 = Double.valueOf(temp[1]);
		if (string.contains("*")) {
			value = String.valueOf(d1 * d2);
		} else {
			value = String.valueOf(d1 / d2);
		}

		return value;
	}

	/**
	 * 执行加减法
	 * @param string
	 * @return
	 * @author ZYWANG 2009-8-31
	 */
	private static String doAdditionAndSubtraction(String string) {
		double d1 = 0;
		double d2 = 0;
		String[] temp = null;
		String value = "";
		if (string.contains("+")) {
			temp = string.split("\\+");
		} else {
			temp = string.split("\\-");
		}

		if (temp.length < 2)
			return string;

		d1 = Double.valueOf(temp[0]);
		d2 = Double.valueOf(temp[1]);
		if (string.contains("+")) {
			value = String.valueOf(d1 + d2);
		} else {
			value = String.valueOf(d1 - d2);
		}

		return value;
	}

	/**
	 * 执行负数运算
	 * @param string
	 * @return
	 * @author ZYWANG 2010-11-8
	 */
	private static String doNegativeOperation(String string) {
		String temp = string.substring(1);
		if (temp.contains("+")) {
			temp = temp.replace("+", "-");
		} else {
			temp = temp.replace("-", "+");
		}
		temp = doAdditionAndSubtraction(temp);
		if (temp.startsWith("-")) {
			temp = temp.substring(1);
		} else {
			temp = "-" + temp;
		}
		return temp;
	}

	public static void main(String[] args) {
		String s = "1-7+8";
		s = computeString(s);
		System.out.println(s);
	}
}

 特别感谢lping2指出了负数运算的计算BUG。

分享到:
评论
2 楼 zywang 2010-11-08  
lping2 写道
有bug :6-6-6-6-6-6 计算错误

多谢指正,对负数的处理的确有问题!
1 楼 lping2 2010-11-04  
有bug :6-6-6-6-6-6 计算错误

相关推荐

    java正则实现解析算术表达式 (仅限+-*/和括号)

    java正则实现解析算术表达式 (仅限+-*/和括号)

    C++实现带括号正整数加减乘除的计算器(代码中提供了测试用例)

    编写一个程序可以完成基本的带括号的四则运算。其中除法(/)是整除,并且在负数除法时向0取整。(C/C++/Java默认的除法就是向0取整,python默认的是向负无穷取整。) 例如计算 100 * ( 2 + 12 ) - (20 / 3) * 2, 结果...

    JAVA基础之java的移位运算

    字符串数组binary 代表了0到15 对应的二进制的值。在本例中,数组各元素的排列顺序显示了变量对应值的二进制代码。数组之所以这样构造是因为变量的值n对应的二进制代码可以被正确的存储在数组对应元素binary[n] 中。...

    使用z3约束求解器进行约束求解(java实现)

    内容概要: z3util可以求解含+-*/和()的约束方程的运算,例如:x=a+b*(y)+1,y=9,a!=0。可传递用“,"分割的约束表达式字符串,传入后...含括号的四则运算的计算算法。 阅读建于: 运行代码时需要配置好java的z3环境。

    EL表达式 (详解)

    ${param}表示返回请求参数中单个字符串的值. ${paramValues}表示返回请求参数的一组 值.pageScope表示页面范围的变量.requestScope表示请求对象的变量. sessionScope表示会话 范围内的变量.applicationScope...

    使用StringBuffer处理的Java计算器

    这是基于StringBuffer处理字符串的一个java计算器,对于不规则的四则运算也进行了处理,会有相应的提示,缺点是处理类没有实现面向对象,实现上主要还是面向过程的。

    JavaScript笔记

    |--字符串 + 布尔值:布尔值转换为字符串true或false |--布尔值 + 布尔值:布尔值转换为数值1或0 7.数据类型转换函数 :(方法前不需要对象调用的:全局函数) |--toString():转换成字符串。所有数据类型均可...

    JAVA面试题最全集

    给定一个C语言函数,要求实现在java类中进行调用。 45.如何获得数组的长度? 46.访问修饰符“public/private/protected/缺省的修饰符”的使用 47.用关键字final修饰一个类或者方法时,有何意义? 48.掌握类和...

    java基础入门教程

    香 港 则 在 今 年 4月 就 举 行 了 全 岛 的 Java杯 比 赛 ,在 计 算 机界掀 起 了 学 习 Java的热 潮 (尤 其 是 在 大 学 生 们 中 ,出 现 了 一 批 Java迷 )。 有 人 预 言 :Java将 是 网 络 上 的 "世 界 语 ...

    java 面试题 总结

    在实现中,assertion就是在程序中的一条语句,它对一个boolean表达式进行检查,一个正确程序必须保证这个boolean表达式的值为true;如果该值为false,说明程序已经处于不正确的状态下,系统将给出警告或退出。...

    Java实验报告(5).doc

    若遇到的是运算符: 4.1 当该运算符的优先级大于栈顶运算符的优先级时,进栈 4.2 若遇到的运算符的优先级小于或等于栈顶运算符的优先级,这表明栈顶运算符的 两个运算对象已经被保存到strResult串中,应将栈顶...

    freemarker总结

    方法变量通常是基于给出的参数计算值在数据模型中定义。 6、 用户自定义FTL指令:宏和变换器 7、 节点 节点变量表示为树型结构中的一个节点,通常在XML处理中使用。 在模板里对sequences和hashes初始化 ...

    整理后java开发全套达内学习笔记(含练习)

    进行高精度运算可以用java.math包中BigDecimal类中的方法。 自动类型提升又称作隐式类型转换。 强制类型转换:int ti; (byte) ti ; 强制转换,丢弃高位 宣告变量名称的同时,加上“final”关键词来限定,这个...

    超级有影响力霸气的Java面试题大全文档

    在实现中,assertion就是在程序中的一条语句,它对一个boolean表达式进行检查,一个正确程序必须保证这个boolean表达式的值为true;如果该值为false,说明程序已经处于不正确的状态下,系统将给出警告或退出。...

    MYSQL常用命令大全

    MySQL以YYYY-MM-DD格式来显示DATE值,但是允许你使用字符串或数字把值赋给DATE列 4.CHAR(M) 型:定长字符串类型,当存储时,总是是用空格填满右边到指定的长度 5.BLOB TEXT类型,最大长度为65535(2^16-1)个字符...

    MySQL命令大全

    MySQL以YYYY-MM-DD格式来显示DATE值,但是允许你使用字符串或数字把值赋给DATE列 4.CHAR(M) 型:定长字符串类型,当存储时,总是是用空格填满右边到指定的长度 5.BLOB TEXT类型,最大长度为(2^16-1)个字符。 6...

    four-arithmetic-gui:自动生成四个算术表达式(GUI版本)

    用户输入的题目数量,系统显示对应的四则运算习题 c. 计时功能。计时非强制性,用户可点击开始计时按钮开启测试模式,在规定时间内完成答题;用户也可直接开始答题,作为练习 d. 正误判断功能。要求用户提交答案后...

    2009达内SQL学习笔记

    DISTINCT必须使用列名,不能使用计算或者表达式。 所有的聚合函数都可以使用。如果指定列名,则DISTINCT只能用于COUNT(列名),DISTINCT不能用于COUNT(*)。 如:Select Distinct name From s_dept; Select ...

    javaSE代码实例

    12.2.2 字符串转换为基本数据类型值 229 12.3 其他常用方法 231 12.3.1 静态工厂方法 231 12.3.2 isNaN方法 232 12.3.3 equals方法 233 12.4 自动打包/解包 -235 12.4.1 自动打包 235 12.4.2 自动解包...

Global site tag (gtag.js) - Google Analytics