Java实现带括号优先级的计算器
这个计算器不仅能够进行四则运算,还支持添加括号进行优先级计算,例如下面算式:
- 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实现带括号优先级的计算器的更多相关文章
- java实现可有括号的android计算器
写了一个android版的计算器,可以计算带括号的表达式,不过前提是:正确的表达式才行 小缺陷是没有做表达式括号的控制,现在还没有想到好的控制方式 package javaAdvanced; impo ...
- Python带括号的计算器
带括号的计算器也是第一个自我感觉完成最好的 毕竟真的弄了一个多星期 虽然前期这路真的很难走 我会努力加油 将Python学好学踏实 参考了两位博主的文章 http://www.cnblogs.co ...
- 使用python开发一个能够计算带括号的复杂表达式的计算器(只支持加减乘除)
使用到了模块re,正则,字典等 # 实现简单的加减乘除括号等运算 # Calculator def calculator(expression): print(expression) import r ...
- java中运算符的优先级
所谓优先级,就是在表达式中的运算顺序.Java 中常用的运算符的优先级如下表所示: 级别为 1 的优先级最高,级别 11 的优先级最低.譬如,x = 7 + 3 * 2 得到的结果是 13 &quo ...
- 慕课网-安卓工程师初养成-3-9 Java中运算符的优先级
来源 http://www.imooc.com/code/1315 所谓优先级,就是在表达式中的运算顺序.Java 中常用的运算符的优先级如下表所示: 级别为 1 的优先级最高,级别 11 的优先级最 ...
- (转载)Java自带的GUI性能监控工具Jconsole以及JisualVM简介
原文链接:http://blog.csdn.net/chendc201/article/details/22905503 1 Jconsole 1.1 简介以及连接 JConsole是一个基于JMX的 ...
- Java课程设计----仿Windows标准型计算器
JAVA课程设计 仿Windows标准型计算器(By Yanboooooooo) 一.团队介绍: 连燕波[组长]:网络1513学生. 张文博[组员]:网络1513学生. 二.项目git地址 码云项目地 ...
- js中new函数后带括号和不带括号的区别
用new创建构造函数的实例时,通常情况下new 的构造函数后面需要带括号(譬如:new Parent()). 有些情况下new的构造函数后带括号和不带括号的情况一致,譬如: function Pare ...
- 解决VS Code开发Python3语言自动补全功能不带括号的问题
Visual Studio Code(以下简称VS Code)用来开发Python3,还是很便利的,本身这个IDE就是轻量级的,才几十兆大小,通过安装插件的方式支持各种语言的开发.界面也美美哒,可以在 ...
随机推荐
- WordPress文章浏览历史插件
选自:http://www.ludou.org/wordpress-recently-viewed.html 最近有很多网友问我,露兜博客右边栏底部的 您刚刚看过 栏目是怎么实现.其实我也是参考的这篇 ...
- 剑指Offer 栈的压入、弹出序列
题目描述 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序.假设压入栈的所有数字均不相等.例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序 ...
- BZOJ 2466: [中山市选2009]树
Sol 树形DP. 听说有非常神奇的高斯消元的做法...orz... 然而我只会 \(O(n)\) 的树形DP. 首先一个点的状态只于他的父节点和子树有关,跟他 子树的子树 和 父亲的父亲 都没有任何 ...
- [翻译]opengl扩展教程2
[翻译]opengl扩展教程2 原文地址https://www.opengl.org/sdk/docs/tutorials/ClockworkCoders/extensions_part2.php [ ...
- Python自动化之IO多路复用
单线程.多线程和异步对比图 灰色的是阻塞 IO多路复用 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方).操作系统的核心 ...
- Docker个人学习总结
最近一段时间学习了下Docker,关于Docker的安装,运用什么的在这里我不会过多的说明,我只说我对于Docker的一些理解,附加我用于记录的少量代码. 刚开始学习Docker的时候,找资料在网上看 ...
- Jquery ajax调用webservice总结
jquery ajax调用webservice(C#)要注意的几个事项: 1.web.config里需要配置2个地方 <httpHandlers> <remove verb ...
- Linq查询非泛型集合要指定Student类型(比如List)
#region Linq to 集合查询非泛型集合要指定Student类型 //ArrayList list = new ArrayList(); //li ...
- Unity3d 枚举某个目录下所有资源
using UnityEngine; using System.Collections; using UnityEditor; using System.Collections.Generic; us ...
- Xcode 必备插件管理器 http://alcatraz.io
各种小插件,其中写注释用的 VVDocumenter 是必备的!