这个计算器不仅能够进行四则运算,还支持添加括号进行优先级计算,例如下面算式:

10+(2*16-20/5)+7*2=52

Java源代码:

 import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Stack; import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField; /**
* 计算器
*/
public class Calculator { /** 数字栈:用于存储表达式中的各个数字 */
private Stack<Long> numberStack = null;
/** 符号栈:用于存储运算符和括号 */
private Stack<Character> symbolStack = null; /**
* 解析并计算四则运算表达式(含括号),返回计算结果
*
* @param numStr
* 算术表达式(含括号)
*/
public long caculate(String numStr) {
numStr = removeStrSpace(numStr); // 去除空格
// 如果算术表达式尾部没有‘=’号,则在尾部添加‘=’,表示结束符
if (numStr.length() > 1 && !"=".equals(numStr.charAt(numStr.length() - 1) + "")) {
numStr += "=";
}
// 检查表达式是否合法
if (!isStandard(numStr)) {
System.err.println("错误:算术表达式有误!");
return 0;
}
// 初始化栈
numberStack = new Stack<Long>();
symbolStack = new Stack<Character>();
// 用于缓存数字,因为数字可能是多位的
StringBuffer temp = new StringBuffer();
// 从表达式的第一个字符开始处理
for (int i = 0; i < numStr.length(); i++) {
char ch = numStr.charAt(i); // 获取一个字符
if (isNumber(ch)) { // 若当前字符是数字
temp.append(ch); // 加入到数字缓存中
} else { // 非数字的情况
String tempStr = temp.toString(); // 将数字缓存转为字符串
if (!tempStr.isEmpty()) {
long num = Long.parseLong(tempStr); // 将数字字符串转为长整型数
numberStack.push(num); // 将数字压栈
temp = new StringBuffer(); // 重置数字缓存
}
// 判断运算符的优先级,若当前优先级低于栈顶的优先级,则先把计算前面计算出来
while (!comparePri(ch) && !symbolStack.empty()) {
long b = numberStack.pop(); // 出栈,取出数字,后进先出
long a = numberStack.pop();
// 取出运算符进行相应运算,并把结果压栈进行下一次运算
switch ((char) symbolStack.pop()) {
case '+':
numberStack.push(a + b);
break;
case '-':
numberStack.push(a - b);
break;
case '*':
numberStack.push(a * b);
break;
case '/':
numberStack.push(a / b);
break;
default:
break;
}
} // while循环结束
if (ch != '=') {
symbolStack.push(new Character(ch)); // 符号入栈
if (ch == ')') { // 去括号
symbolStack.pop();
symbolStack.pop();
}
}
}
} // for循环结束 return numberStack.pop(); // 返回计算结果
} /**
* 去除字符串中的所有空格
*/
private String removeStrSpace(String str) {
return str != null ? str.replaceAll(" ", "") : "";
} /**
* 检查算术表达式的基本合法性,符合返回true,否则false
*/
private boolean isStandard(String numStr) {
if (numStr == null || numStr.isEmpty()) // 表达式不能为空
return false;
Stack<Character> stack = new Stack<Character>(); // 用来保存括号,检查左右括号是否匹配
boolean b = false; // 用来标记'='符号是否存在多个
for (int i = 0; i < numStr.length(); i++) {
char n = numStr.charAt(i);
// 判断字符是否合法
if (!(isNumber(n) || "(".equals(n + "") || ")".equals(n + "")
|| "+".equals(n + "") || "-".equals(n + "")
|| "*".equals(n + "") || "/".equals(n + "")
|| "=".equals(n + ""))) {
return false;
}
// 将左括号压栈,用来给后面的右括号进行匹配
if ("(".equals(n + "")) {
stack.push(n);
}
if (")".equals(n + "")) { // 匹配括号
if (stack.isEmpty() || !"(".equals((char) stack.pop() + "")) // 括号是否匹配
return false;
}
// 检查是否有多个'='号
if ("=".equals(n + "")) {
if (b)
return false;
b = true;
}
}
// 可能会有缺少右括号的情况
if (!stack.isEmpty())
return false;
// 检查'='号是否不在末尾
if (!("=".equals(numStr.charAt(numStr.length() - 1) + "")))
return false;
return true;
} /**
* 判断字符是否是0-9的数字
*/
private boolean isNumber(char num) {
if (num >= '0' && num <= '9')
return true;
return false;
} /**
* 比较优先级:如果当前运算符比栈顶元素运算符优先级高则返回true,否则返回false
*/
private boolean comparePri(char symbol) {
if (symbolStack.empty()) { // 空栈返回ture
return true;
} // 符号优先级说明(从高到低):
// 第1级: (
// 第2级: * /
// 第3级: + -
// 第4级: ) char top = (char) symbolStack.peek(); // 查看堆栈顶部的对象,注意不是出栈
if (top == '(') {
return true;
}
// 比较优先级
switch (symbol) {
case '(': // 优先级最高
return true;
case '*': {
if (top == '+' || top == '-') // 优先级比+和-高
return true;
else
return false;
}
case '/': {
if (top == '+' || top == '-') // 优先级比+和-高
return true;
else
return false;
}
case '+':
return false;
case '-':
return false;
case ')': // 优先级最低
return false;
case '=': // 结束符
return false;
default:
break;
}
return true;
} // 测试
public static void main(String args[]) {
String num = "10 + (2*16-20/5) + 7*2 "; // 默认的算式
// 创建一个窗口
JFrame win = new JFrame("计算器");
Container con = win.getContentPane();
JPanel pa = new JPanel();
pa.add(new JLabel("输入算式:")); // 添加一个标签
final JTextField formulaText = new JTextField(num, 20); // 算式输入框
pa.add(formulaText);
pa.add(new JLabel("="));
final JTextField resultText = new JTextField(8); // 结果文本框
pa.add(resultText);
con.add(pa); JButton bn = new JButton("计算"); // 实例化按钮对象
con.add(bn, BorderLayout.EAST); // 将按钮添加到右边
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置关闭窗口退出程序
win.pack(); // 自动调整大小
win.setLocationRelativeTo(null); // 设置窗口居中于屏幕
win.setVisible(true); // 显示窗口 // 添加按钮点击事件
bn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) { // 每当按钮点击时调用该方法
/* 计算器操作 */
Calculator cal = new Calculator();
String numStr = formulaText.getText(); // 获得算式文本框中的文字
long result = cal.caculate(numStr); // 计算算式的结果
numStr = cal.removeStrSpace(numStr); // 去空格
formulaText.setText(numStr); // 将去空格的算式放回算式文本框中
resultText.setText(result + ""); // 在结果文本框中显示结果
}
});
}
}

运行结果:

优化支持浮点数计算:

import java.math.BigDecimal;
import java.util.Stack; /**
* 算式计算
*/
public class FormulaUtil { private int scale; // 进行除法出现无线循环小数时保留的精度 /** 数字栈:用于存储表达式中的各个数字 */
private Stack<BigDecimal> numberStack = null;
/** 符号栈:用于存储运算符和括号 */
private Stack<Character> symbolStack = null; public FormulaUtil(int scale) {
super();
this.scale = scale;
} public FormulaUtil() {
this(32);
} /**
* 解析并计算四则运算表达式(含括号优先级),返回计算结果
*
* @param numStr
* 算术表达式(含括号)
*/
public BigDecimal caculate(String numStr) {
numStr = removeStrSpace(numStr); // 去除空格
// 如果算术表达式尾部没有‘=’号,则在尾部添加‘=’,表示结束符
if (numStr.length() > 1
&& !"=".equals(numStr.charAt(numStr.length() - 1) + "")) {
numStr += "=";
}
// 检查表达式是否合法
if (!isStandard(numStr)) {
System.err.println("错误:算术表达式有误!");
return null;
}
// 初始化栈
if (numberStack == null) {
numberStack = new Stack<BigDecimal>();
}
numberStack.clear();
if (symbolStack == null) {
symbolStack = new Stack<Character>();
}
symbolStack.clear();
// 用于缓存数字,因为数字可能是多位的
StringBuffer temp = new StringBuffer();
// 从表达式的第一个字符开始处理
for (int i = 0; i < numStr.length(); i++) {
char ch = numStr.charAt(i); // 获取一个字符
if (isNumber(ch)) { // 若当前字符是数字
temp.append(ch); // 加入到数字缓存中
} else { // 非数字的情况
String tempStr = temp.toString(); // 将数字缓存转为字符串
if (!tempStr.isEmpty()) {
// long num = Long.parseLong(tempStr); // 将数字字符串转为长整型数
BigDecimal num = new BigDecimal(tempStr);
numberStack.push(num); // 将数字压栈
temp = new StringBuffer(); // 重置数字缓存
}
// 判断运算符的优先级,若当前优先级低于栈顶的优先级,则先把计算前面计算出来
while (!comparePri(ch) && !symbolStack.empty()) {
BigDecimal b = numberStack.pop(); // 出栈,取出数字,后进先出
BigDecimal a = numberStack.pop();
// 取出运算符进行相应运算,并把结果压栈进行下一次运算
switch ((char) symbolStack.pop()) {
case '+':
numberStack.push(a.add(b));
break;
case '-':
numberStack.push(a.subtract(b));
break;
case '*':
numberStack.push(a.multiply(b));
break;
case '/':
try {
numberStack.push(a.divide(b));
} catch (java.lang.ArithmeticException e) {
// 进行除法出现无限循环小数时,就会抛异常,此处设置精度重新计算
numberStack.push(a.divide(b, this.scale,
BigDecimal.ROUND_HALF_EVEN));
}
break;
default:
break;
}
} // while循环结束
if (ch != '=') {
symbolStack.push(new Character(ch)); // 符号入栈
if (ch == ')') { // 去括号
symbolStack.pop();
symbolStack.pop();
}
}
}
} // for循环结束 return numberStack.pop(); // 返回计算结果
} /**
* 去除字符串中的所有空格
*/
private String removeStrSpace(String str) {
return str != null ? str.replaceAll(" ", "") : "";
} /**
* 检查算术表达式的基本合法性,符合返回true,否则false
*/
private boolean isStandard(String numStr) {
if (numStr == null || numStr.isEmpty()) // 表达式不能为空
return false;
Stack<Character> stack = new Stack<Character>(); // 用来保存括号,检查左右括号是否匹配
boolean b = false; // 用来标记'='符号是否存在多个
for (int i = 0; i < numStr.length(); i++) {
char n = numStr.charAt(i);
// 判断字符是否合法
if (!(isNumber(n) || "(".equals(n + "") || ")".equals(n + "")
|| "+".equals(n + "") || "-".equals(n + "")
|| "*".equals(n + "") || "/".equals(n + "") || "=".equals(n
+ ""))) {
return false;
}
// 将左括号压栈,用来给后面的右括号进行匹配
if ("(".equals(n + "")) {
stack.push(n);
}
if (")".equals(n + "")) { // 匹配括号
if (stack.isEmpty() || !"(".equals((char) stack.pop() + "")) // 括号是否匹配
return false;
}
// 检查是否有多个'='号
if ("=".equals(n + "")) {
if (b)
return false;
b = true;
}
}
// 可能会有缺少右括号的情况
if (!stack.isEmpty())
return false;
// 检查'='号是否不在末尾
if (!("=".equals(numStr.charAt(numStr.length() - 1) + "")))
return false;
return true;
} /**
* 判断字符是否是0-9的数字
*/
private boolean isNumber(char num) {
if ((num >= '0' && num <= '9') || num == '.')
return true;
return false;
} /**
* 比较优先级:如果当前运算符比栈顶元素运算符优先级高则返回true,否则返回false
*/
private boolean comparePri(char symbol) {
if (symbolStack.empty()) { // 空栈返回ture
return true;
} // 符号优先级说明(从高到低):
// 第1级: (
// 第2级: * /
// 第3级: + -
// 第4级: ) char top = (char) symbolStack.peek(); // 查看堆栈顶部的对象,注意不是出栈
if (top == '(') {
return true;
}
// 比较优先级
switch (symbol) {
case '(': // 优先级最高
return true;
case '*': {
if (top == '+' || top == '-') // 优先级比+和-高
return true;
else
return false;
}
case '/': {
if (top == '+' || top == '-') // 优先级比+和-高
return true;
else
return false;
}
case '+':
return false;
case '-':
return false;
case ')': // 优先级最低
return false;
case '=': // 结束符
return false;
default:
break;
}
return true;
} // 测试
public static void main(String args[]) {
String numStr = "10.000000000000000009 + (2*16-20/4) + 7*2.5 "; // 默认的算式
BigDecimal result = new FormulaUtil().caculate(numStr); // 计算算式的结果
System.out.println(numStr + "=");
System.out.println(result);
}
}

  

Java实现带括号优先级的计算器的更多相关文章

  1. java实现可有括号的android计算器

    写了一个android版的计算器,可以计算带括号的表达式,不过前提是:正确的表达式才行 小缺陷是没有做表达式括号的控制,现在还没有想到好的控制方式 package javaAdvanced; impo ...

  2. Python带括号的计算器

    带括号的计算器也是第一个自我感觉完成最好的 毕竟真的弄了一个多星期 虽然前期这路真的很难走  我会努力加油  将Python学好学踏实 参考了两位博主的文章 http://www.cnblogs.co ...

  3. 使用python开发一个能够计算带括号的复杂表达式的计算器(只支持加减乘除)

    使用到了模块re,正则,字典等 # 实现简单的加减乘除括号等运算 # Calculator def calculator(expression): print(expression) import r ...

  4. java中运算符的优先级

    所谓优先级,就是在表达式中的运算顺序.Java 中常用的运算符的优先级如下表所示: 级别为 1 的优先级最高,级别 11 的优先级最低.譬如,x = 7 + 3 * 2  得到的结果是 13 &quo ...

  5. 慕课网-安卓工程师初养成-3-9 Java中运算符的优先级

    来源 http://www.imooc.com/code/1315 所谓优先级,就是在表达式中的运算顺序.Java 中常用的运算符的优先级如下表所示: 级别为 1 的优先级最高,级别 11 的优先级最 ...

  6. (转载)Java自带的GUI性能监控工具Jconsole以及JisualVM简介

    原文链接:http://blog.csdn.net/chendc201/article/details/22905503 1 Jconsole 1.1 简介以及连接 JConsole是一个基于JMX的 ...

  7. Java课程设计----仿Windows标准型计算器

    JAVA课程设计 仿Windows标准型计算器(By Yanboooooooo) 一.团队介绍: 连燕波[组长]:网络1513学生. 张文博[组员]:网络1513学生. 二.项目git地址 码云项目地 ...

  8. js中new函数后带括号和不带括号的区别

    用new创建构造函数的实例时,通常情况下new 的构造函数后面需要带括号(譬如:new Parent()). 有些情况下new的构造函数后带括号和不带括号的情况一致,譬如: function Pare ...

  9. 解决VS Code开发Python3语言自动补全功能不带括号的问题

    Visual Studio Code(以下简称VS Code)用来开发Python3,还是很便利的,本身这个IDE就是轻量级的,才几十兆大小,通过安装插件的方式支持各种语言的开发.界面也美美哒,可以在 ...

随机推荐

  1. iOS企业级开发初级课程-表视图(13集)

    首先了解了表视图的组成.表视图类的构成.表视图的分类以及表视图的两个重要协议(委托协议和数据源协议),对表视图有了一个整体上的认识.接下来我们掌握了如何实现简单表视图和分节表视图,以及表视图中索引.搜 ...

  2. http基础实战

    1.需求 了解http的基础知识,能看懂chrome下网络的情况 2.前置知识 下面是tcp/ip协议的一些东西,今天就只用了解应用层的http就够了. 3.http是什么 我们在网上浏览网页,会发送 ...

  3. iOS 简单音乐播放器 界面搭建

    如图搭建一个音乐播放器界面,具备以下几个简单功能: 1,界面协调,整洁. 2,点击播放,控制进度条. 3.三收藏歌曲,点击收藏,心形收藏标志颜色加深. 4,左右按钮,切换歌曲图片和标题. 5,点击中间 ...

  4. java计算时间差

    比如:现在是2016-03-26 13:31:40        过去是:2016-01-02 11:30:24 我现在要获得两个日期差,差的形式为:XX天XX小时XX分XX秒 方法一: DateFo ...

  5. Delphi实现窗体内嵌其他应用程序窗体

    实现原理是启动一个应用程序,通过ProcessID得到窗体句柄,然后对其设定父窗体句柄为本程序某控件句柄(本例是窗体内一个Panel的句柄),这样就达成了内嵌的效果. 本文实现的是内嵌一个记事本程序, ...

  6. BZOJ 3362: [Usaco2004 Feb]Navigation Nightmare 导航噩梦

    Description 给你每个点与相邻点的距离和方向,求两点间的曼哈顿距离. \(n \leqslant 4\times 10^4\) . Sol 加权并查集. 像向量合成一样合并就可以了,找 \( ...

  7. hadoop学习过程中一系列问题

    12---修改host .修改主机名5.1 修改当前会话的主机名sudo hostname SY-0217查看当前会话的主机名hostname默认是我装Linux 虚机时输入的名字Ubuntu5.2 ...

  8. 使用html5 FileReader获取图片,并异步上传到服务器(不使用iframe)

    使用html5 FileReader获取图片,并异步上传到服务器(不使用iframe)   原理: 1.使用FileReader 读取图片的base64编码 2.使用ajax,把图片的base64编码 ...

  9. js原生的url操作函数,及使用方法。(附:下边还有jquery对url里的中文解码函数)

    js原生的url操作函数,完善的. /*****************************/ /* 动态修改url */ /*****************************/ var ...

  10. JavaScript——exec和match

    题目17:Read the following javascript code: var someText="web2.0 .net2.0";var pattern=/(\w+)( ...