这篇文章主要为大家详细介绍了Java实现简易计算器,逆波兰表达式,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
本文实例为大家分享了Java实现简易计算器的具体代码,供大家参考,具体内容如下
程序的运行环境为Windows10 ,编译环境为IDEA。
计算器有以下功能和要求:能够计算复杂表达式,实现对多位数和负数以及小数的多则复杂计算
已完善功能(Bug):
1,能够计算大数字,小数,负数
2,小数点,运算符等不能连续输入(例如 ..,++,**等)
3,小数点前没有数字时自动补0并在输入框显示“0.”若小数点前是数字,且前面的数字串里含有".",则不能继续输入小数点(“.”---”0.“ ,1.11后面不能继续输入小数点)
4,‘(’左边和‘)’右边输入数字时,有运算符不做操作,无运算符自动补"*",")"后跟"(',在中间加‘*’(例如“7(”--“7*(”,“)7”--“(*7)”,“(1+1)(2+2)”--“(1+1)*(2+2)”)
5,输入的")"不能多于"(",且相邻()之间不能为空(“()”--X,“((1+2)))--X)
6,能计算负数,符号前面没有数字则补0 (-6-1 -- 0-6-1)
7,运算符除"-"号外不能第一个输入,若不是第一次计算,则可以直接输入,将上一个表达式的结果作为此次表达式的第一个运算数
8,查看历史记录,清空当前记录,清空历史记录,退格操作
运行结果如图:
实现过程:
一、计算器界面设计
1. 初始化界面
通过 this 方法设置包括界面的大小,界面的位置(可根据屏幕设置中间位置),按键北面和中间排版及其颜色和大小,采用GridLayout网格布局
通过循环设置按键的位置,并将运算符加粗,并将所有按键和排版串联到界面上
class Main {
public static class Calculator extends JFrame implements ActionListener {
// 初始化界面
public void init() {
this.setTitle("计算器");
history.setEditable(false);
history.setFont(new Font("宋体", Font.PLAIN, 30));
this.setSize(477, 577); //界面大小
this.setLayout(new BorderLayout());
this.setResizable(false);
this.setLocationRelativeTo(null); //界面位置设置居中
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
//北面的控件
private final JPanel key_north = new JPanel();
private final JTextField input_text = new JTextField();
private final JTextArea history = new JTextArea();
private final JButton c_btn = new JButton("C");
private final JButton ALLc_btn = new JButton("AC");
//中间的控件
private final JPanel center = new JPanel();
//将界面串联
public Calculator() throws HeadlessException {
this.init();
this.addNorthCompent();
this.addCenterButton();
}
//添加北面控键
public void addNorthCompent() {
this.history.setPreferredSize(new Dimension(350, 200));
this.input_text.setPreferredSize(new Dimension(450, 30));//输入框的大小
input_text.setBackground(new Color(127,255,212));
this.key_north.setBackground(new Color(193,255,193));
this.history.setBackground(new Color(193,255,120));
key_north.add(input_text);
key_north.add(history);
this.c_btn.setForeground(new Color(0,139,139));//按键颜色
this.ALLc_btn.setBackground(new Color(0,205,205));
key_north.add(c_btn);
key_north.add(ALLc_btn);
c_btn.setBackground(Color.CYAN);
c_btn.addActionListener(new ActionListener() { //为清除操作设置监听
@Override
public void actionPerformed(ActionEvent e) {
firstint = "";
input_text.setText("");
}
});
ALLc_btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
input_text.setText("");
firstint = "";
hitory = "";
history.setText("");
}
});
this.add(key_north, BorderLayout.NORTH);
}
//添加中间按键
public void addCenterButton() {
String key_text = "H()←123+456-789*0.=/";//中间控件排版
this.center.setLayout(new GridLayout(5, 4));
String regex = "[+\\-*/=H()←]";
for (int i = 0; i < 20; i++) { //初始化按键
String temp = key_text.substring(i, i + 1);
JButton key = new JButton();
key.setFont(new Font("宋体",Font.BOLD,20));
key.setForeground(new Color(69,139,116));
key.setBackground(new Color(193,255,193));
key.setText(temp);
if (temp.matches(regex)) { //将运算符加粗并更改颜色
key.setFont(new Font("粗体", Font.BOLD, 30));
key.setForeground(new Color(102,205,170));
}
key.addActionListener(this);
center.add(key);
}
this.add(center, BorderLayout.CENTER);
}
2. 计算器功能设计
设置监听
设两个空字符串,一个用来保存表达式,另一个用来保存历史记录
为所有按键设置监听功能,将输入的表达式显示到文本框的右边,并实现计算结果,查看历史记录,清空历史记录,计算器表达式退格功能,判断表达式合法性.
@Override
public void actionPerformed(ActionEvent e) { //监听功能
String strings = e.getActionCommand();//保存记录
//JOptionPane.showMessageDialog(this,strings);//监听
if ("0123456789".contains(strings)) {
if (Objects.equals(firstint, "")) { //输入新的表达式,清除掉上一个表达式结果
firstint+=strings;
this.input_text.setText(strings);
this.input_text.setHorizontalAlignment(JTextField.RIGHT);//显示到右边
}else if(strings.equals("0")){
if (Objects.equals(firstint, "0")) {
this.input_text.setText(firstint);
}else {
int index = 0;
for ( int i=firstint.length()-1;i >=0;i-- ) {
if(isSymbol(firstint.substring(index))){
index=i;
}
}
if (!firstint.substring(index+1, firstint.length() - 1).equals("0")) {
firstint += strings;
}
this.input_text.setText(firstint);
}
} else if(firstint.charAt(firstint.length()-1)==')'){ //)后输入数字补*号
firstint+="*"+strings;
this.input_text.setText(firstint);
}else {this.input_text.setText(input_text.getText() + strings);//将输入的数记录并将之前的数放到前面
this.input_text.setHorizontalAlignment(JTextField.RIGHT);//显示到右边
firstint += strings;
System.out.println(firstint);}
} else if (strings.equals(".")) {
if (Objects.equals(firstint, "")) {
if (!Objects.equals(ans, "")) {
firstint = ans + ".";
this.input_text.setText(firstint);
}else {this.input_text.setText(input_text.getText() + "0" + strings);
this.input_text.setHorizontalAlignment(JTextField.RIGHT); //自带补0
firstint = "0" + strings;}
} else if(firstint.charAt(firstint.length() - 1) == ')'){ //)后输入小数点补0
firstint =firstint+ "*0"+strings;
this.input_text.setText(firstint);
}
else if (firstint.charAt(firstint.length() - 1) == '.') { //不能连续小数点
this.input_text.setText(firstint);
this.input_text.setHorizontalAlignment(JTextField.RIGHT);
} else if (!ToPolland.isNumber(String.valueOf(firstint.charAt(firstint.length() - 1))) && !String.valueOf(firstint.charAt(firstint.length() - 1)).equals(".")) {
this.input_text.setText(input_text.getText() + "0" + strings); //前一个既不是数字也不是小数补0
this.input_text.setHorizontalAlignment(JTextField.RIGHT);
firstint = firstint + "0" + strings;
} else if (ToPolland.isNumber(String.valueOf(firstint.charAt(firstint.length() - 1)))) {//如果前面是数字之间输入
int count = 0, i = 0;
for (i = firstint.length() - 1; i > 0; i--) { //查找前面的数字串中有没有小数点
if (ToPolland.isSymbol(String.valueOf(firstint.charAt(i)))) {
break;
}//直到遇到下一个运算符时结束查找
else if (firstint.charAt(i) == '.') {
count++;
}
}
if (count == 0) { //判断前面的数字串没有小数点
this.input_text.setText(input_text.getText() + strings);
this.input_text.setHorizontalAlignment(JTextField.RIGHT);
firstint = firstint + strings;
}
}
} else if (strings.matches("[+\\-*/]")) {
if (Objects.equals(firstint, "")) { //运算符前必须有运算数
if (!Objects.equals(ans, "")) {
firstint += ans+strings;
this.input_text.setText(firstint);
}
if(strings.equals("-")){ //减号第一个输入当做负号
this.input_text.setHorizontalAlignment(JTextField.RIGHT);
this.input_text.setText("-");
firstint += strings;
}
//JOptionPane.showMessageDialog(null, "请先输入操作数");
}else if(firstint.charAt(firstint.length()-1)=='.'){ //小数点后不能跟运算符
this.input_text.setText(firstint);
}
else if (firstint.charAt(firstint.length() - 1)=='('){ //(后只能跟-号运算符
if(strings.equals("-")){
firstint+=strings;
this.input_text.setText(firstint);
}
}
else if (ToPolland.isSymbol(String.valueOf(firstint.charAt(firstint.length() - 1)))&&strings!="-") {
this.input_text.setText(firstint);
} else {
this.input_text.setText(input_text.getText() + strings);
firstint = firstint + strings;
System.out.println(firstint);
}
} else if (strings.matches("[()]{1}")) {
if (strings.equals("(")) {
if(Objects.equals(firstint, "") ||firstint.charAt(firstint.length()-1)=='('){
firstint+="(";
this.input_text.setText(firstint);
this.input_text.setHorizontalAlignment(JTextField.RIGHT);
}else if(firstint.charAt(firstint.length() - 1) == ')'){
firstint+="*"+strings;
this.input_text.setText(firstint);
} else if(ToPolland.isNumber(String.valueOf(firstint.charAt(firstint.length()-1)))){
firstint+="*"+strings;
this.input_text.setText(firstint);
}else if(ToPolland.isSymbol(String.valueOf(firstint.charAt(firstint.length()-1)))){
firstint+=strings;this.input_text.setText(firstint);
}
System.out.println(firstint);
} else if (strings.equals(")") && firstint != "") {
if(ToPolland.isSymbol(String.valueOf(firstint.charAt(firstint.length()-1)))){
this.input_text.setText(firstint);
}else if (firstint.charAt(firstint.length() - 1) != '(') {
int count1 = 0, count2 = 1;
for (int i = 0; i < firstint.length(); i++) { //找出()的个数
if (firstint.charAt(i) == '(') {
count1++;
}
if (firstint.charAt(i) == ')') {
count2++;
}
}
if (count1 >= count2) { (个数必须大于等于)个数
this.input_text.setText(input_text.getText() + strings);
firstint = firstint + strings;
System.out.println(firstint);
}
}
}
} else if (strings.equals("=")) { //计算结果
try {
if(firstint.charAt(firstint.length()-1)=='.'){
firstint=firstint.substring(0,firstint.length()-2);
}System.out.println(firstint);
StringBuilder builder = new StringBuilder();
List<String> list = toPolland(ToPolland.toList(firstint));
list.forEach(builder::append);
System.out.println("算式表达式:" + firstint);
System.out.println("转逆波兰表达式:" + builder);
System.out.println("转逆波兰表达式计算结果:" + firstint + "=" + ToPolland.calculate(list));
ans = String.valueOf(ToPolland.calculate(list));
this.input_text.setText("" + ToPolland.calculate(list));
hitory += firstint + "=" + ToPolland.calculate(list) + "\n";
firstint = "";
} catch (Exception e1) {
JOptionPane.showMessageDialog(null, "表达式错误");
firstint = "";
this.input_text.setText("");
}
} else if (strings.equals("H")) { //查看历史记录
history.setFont(new Font("宋体", Font.BOLD, 20));
this.history.setText(hitory);
} else if (strings.equals("C")) { //清空当前记录
firstint = "";
this.input_text.setText("");
} else if (strings.equals("AC")) { //清空历史记录
firstint = "";
hitory = "";
this.history.setText("");
this.input_text.setText("");
} else if (strings.equals("←") && firstint.length() != 0) { //退格
firstint = firstint.substring(0, firstint.length() - 1);
System.out.println(firstint);
this.input_text.setText("" + firstint.substring(0, firstint.length()));
}
}
}
二、表达式求值
1、将中缀表达式转为 list 结构
中缀转后缀表达式时需要先将中缀表达式转为 list 结构,在这个过程中,可以分析表达式的合理性,将表达式进行处理(去掉空格及其他错误的符号),判断表达式的正确性并给予反馈 . 我们处理的时候还需要注意多位数字的处理,可以利用一个字符数组对多位数字和小数进行拼接
//将表达式存入list
public static List<String> toList(String strings) {
strings = tList(strings);
if (strings == null || strings.length() <= 0) {
throw new NullPointerException("表达式不能为空!");
}
// 去掉不合法的符号
strings = strings.replaceAll("\\s*|\t|\r|\n", "");
List<String> list = new ArrayList<>();
char[] chars = strings.toCharArray();
String ch="",str="";
for (int i = 0; i < chars.length; i++) {
// 判断是否是数字
if (!Character.isDigit((chars[i]))) {
list.add(String.valueOf(chars[i]));
} else { //如果是数字,就判断下一个是不是数字,如果是就进行组合(循环),然后录入list
do {
ch = String.valueOf(chars[i]); //读取一个字符
str += ch; //进行拼接
i++;
//不是最后一个字符,并且下一个还是数字或者小数点,就进行循环
} while ((i < strings.length()) && ((chars[i] <= 57
&& chars[i] >= 48) || '.' == chars[i]));
list.add(str);//将拼接的字符串录入到list
str = "";i--;
System.out.println(list);//这里一定要将str置位初值
}
}
return list;
}
需要注意的是当输入的表达式中存在负数时,需要在负号前面补0,或者将负号后面的表达式中的一个计算符取反,否则转为逆波兰表达式后得不到正确的结果。
//表达式中存在负数时,后面的逆波兰表达式算法无法得到正确结果,需要补0
public static String tList(String strings) {
String stringBuilder = "";
if(strings.charAt(0)=='-'){//如果第一个字符是‘-',在负号前面补0
stringBuilder+= "0";
}
stringBuilder+=strings.charAt(0); //将第一个‘-'号接到0后面
//如果遇到负号,并且负号前面的符号不是数字,在负号前面补0
for (int i = 1; i < strings.length(); i++) {
if (strings.charAt(i) == '-' && (isNumber(String.valueOf(strings.charAt(i - 1))) == false)) {
stringBuilder += "0" + strings.charAt(i);
} else stringBuilder += strings.charAt(i);//没有负号则直接拼接
}
return stringBuilder;
}
2、逆波兰表达式的转化(单栈法)
采用单栈来和一个队列对表达式进行操作,也可以采用双栈法处理表达式
构造判断数字,计算符以及优先级的方法
实现代码如下:
//转逆波兰表达式
public static List<String> toPolland(List<String> list) {
Stack<String> s1 = new Stack();
List<String> s2 = new ArrayList<>();
// 从左至右扫描中缀表达式;
for (String item : list) {
// 遇到操作数时,将其压s2;
if (Pattern.matches("-?[0-9]+(\\.[0-9]+)?", item)) {
s2.add(item);
}//遇到操作符时,比较其与栈顶的操作符的优先级
if (isSymbol(item)) {
while (s1.size() > 0 && isSymbol(s1.peek()) && priority(item) <= priority(s1.peek())) {
s2.add(s1.pop());
}
s1.push(item);
}
if (item.equals("(")) { //右括号直接入栈
s1.push(item);
}
if (item.equals(")")) { //遇到右括号,将左括号之前的操作符全部出栈
while (!s1.peek().equals("(")) {
s2.add(s1.pop());
}
// 将左边的括号,弹栈
s1.pop();
}
}
while (s1.size() > 0) { //将剩余的操作符全部入栈
s2.add(s1.pop());
}
return s2;
}
判断数字和运算符已经比较运算符优先级:
//判断是否为数字
public static boolean isNumber(String str) {
return Pattern.matches("-?[0-9]+(\\.[0-9]+)?", str);
}
//是否是运算符
public static boolean isSymbol(String str) {
return "+-*/".contains(str);
}
//返回运算符的优先级
public static int priority(String value) {
if ("+-".contains(value)) {
return 1;
} else if ("*/".contains(value)) {
return 2;
} else {
throw new RuntimeException("暂不支持操作符:" + value);
}
}
3、逆波兰表达式(后缀表达式)的计算
首先准备一个栈Res_Stack.
1、从左开始向右遍历后缀表达式的元素。
2、如果取到的元素是操作数,直接入栈Res_Stack,如果是运算符,从栈中弹出2个数进行运算,然后把运算结果入栈
3、当遍历完后缀表达式时,计算结果就保存在栈里了。
算法思想:
代码如下:
//逆波兰表达式的计算
public static BigDecimal calculate(List<String> nipollands) {
if (nipollands == null || nipollands.size() <= 1) {
throw new NullPointerException("逆波兰表达式列表不能为空!");
}
Stack<BigDecimal> stack = new Stack();
for (String nipolland : nipollands) {
if (isNumber(nipolland)) { //数字直接入栈
stack.push(new BigDecimal(nipolland));
} else { //遇到操作符取出两个数进行对应的计算,并将计算结果入栈
BigDecimal number1 = stack.pop();
BigDecimal number2 = stack.pop();
BigDecimal result;
switch (nipolland) {
case "+" -> result=number2.add(number1);
case "-" -> result=number2.subtract(number1);
case "*" -> result=number2.multiply(number1);
case "/" -> result=number2.divide(number1, 3,RoundingMode.HALF_UP);
default -> throw new RuntimeException("不合法操作符:" + nipolland);
}
stack.push(result);//遍历字符串后得到的栈顶既为逆波兰表达式计算结果
}
}
return stack.pop();
}
完整代码:
package com.company;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.regex.Pattern;
import static com.company.ToPolland.toPolland;
class Main {
public static class Calculator extends JFrame implements ActionListener {
// 初始化界面
public void init() {
this.setTitle("计算器");
history.setEditable(false);
history.setFont(new Font("宋体", Font.PLAIN, 30));
this.setSize(477, 577); //界面大小
this.setLayout(new BorderLayout());
this.setResizable(false);
this.setLocationRelativeTo(null); //界面位置设置居中
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
//北面的控件
private final JPanel key_north = new JPanel();
private final JTextField input_text = new JTextField();
private final JTextArea history = new JTextArea();
private final JButton c_btn = new JButton("C");
private final JButton ALLc_btn = new JButton("AC");
//中间的控件
private final JPanel center = new JPanel();
//将界面串联
public Calculator() throws HeadlessException {
this.init();
this.addNorthCompent();
this.addCenterButton();
}
//添加北面控键
public void addNorthCompent() {
this.history.setPreferredSize(new Dimension(350, 200));
this.input_text.setPreferredSize(new Dimension(450, 30));//输入框的大小
input_text.setBackground(new Color(127,255,212));
this.key_north.setBackground(new Color(193,255,193));
this.history.setBackground(new Color(193,255,120));
key_north.add(input_text);
key_north.add(history);
this.c_btn.setForeground(new Color(0,139,139));//按键颜色
this.ALLc_btn.setBackground(new Color(0,205,205));
key_north.add(c_btn);
key_north.add(ALLc_btn);
c_btn.setBackground(Color.CYAN);
c_btn.addActionListener(new ActionListener() { //为清除操作设置监听
@Override
public void actionPerformed(ActionEvent e) {
firstint = "";
input_text.setText("");
}
});
ALLc_btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
input_text.setText("");
firstint = "";
hitory = "";
history.setText("");
}
});
this.add(key_north, BorderLayout.NORTH);
}
//添加中间按键
public void addCenterButton() {
String key_text = "H()←123+456-789*0.=/";//中间控件排版
this.center.setLayout(new GridLayout(5, 4));
String regex = "[+\\-*/=H()←]";
for (int i = 0; i < 20; i++) { //初始化按键
String temp = key_text.substring(i, i + 1);
JButton key = new JButton();
key.setFont(new Font("宋体",Font.BOLD,20));
key.setForeground(new Color(69,139,116));
key.setBackground(new Color(193,255,193));
key.setText(temp);
if (temp.matches(regex)) { //将运算符加粗并更改颜色
key.setFont(new Font("粗体", Font.BOLD, 30));
key.setForeground(new Color(102,205,170));
}
key.addActionListener(this);
center.add(key);
}
this.add(center, BorderLayout.CENTER);
}
private String firstint = "";//保存表达式
static String hitory = "";//保存历史记录
static String ans = "";
@Override
public void actionPerformed(ActionEvent e) { //监听功能
String strings = e.getActionCommand();//保存记录
//JOptionPane.showMessageDialog(this,strings);//监听
if ("0123456789".contains(strings)) {
if (firstint == "") {
firstint+=strings;
this.input_text.setText(strings);
this.input_text.setHorizontalAlignment(JTextField.RIGHT);//显示到右边
}else if(firstint.charAt(firstint.length()-1)==')'){
firstint+="*"+strings;
this.input_text.setText(firstint);
}else {this.input_text.setText(input_text.getText() + strings);//将输入的数记录并将之前的数放到前面
this.input_text.setHorizontalAlignment(JTextField.RIGHT);//显示到右边
firstint += strings;
System.out.println(firstint);}
} else if (strings.equals(".")) {
if (firstint == "") {
this.input_text.setText(input_text.getText() + "0" + strings);
this.input_text.setHorizontalAlignment(JTextField.RIGHT);
firstint = "0" + strings;
} else if(firstint.charAt(firstint.length() - 1) == ')'){
firstint =firstint+ "*0"+strings;
this.input_text.setText(firstint);
}
else if (firstint.charAt(firstint.length() - 1) == '.') { //不能连续小数点
this.input_text.setText(firstint);
this.input_text.setHorizontalAlignment(JTextField.RIGHT);
} else if (!ToPolland.isNumber(String.valueOf(firstint.charAt(firstint.length() - 1))) && String.valueOf(firstint.charAt(firstint.length() - 1)) != ".") {
this.input_text.setText(input_text.getText() + "0" + strings); //前一个既不是数字也不是小数补0
this.input_text.setHorizontalAlignment(JTextField.RIGHT);
firstint = firstint + "0" + strings;
} else if (ToPolland.isNumber(String.valueOf(firstint.charAt(firstint.length() - 1)))) {//如果前面是数字之间输入
int count = 0, i = 0;
for (i = firstint.length() - 1; i > 0; i--) { //查找前面的数字串中有没有小数点
if (ToPolland.isSymbol(String.valueOf(firstint.charAt(i)))) {
break;
}//直到遇到下一个运算符时结束查找
else if (firstint.charAt(i) == '.') {
count++;
}
}
if (count == 0) { //判断前面的数字串没有小数点
this.input_text.setText(input_text.getText() + strings);
this.input_text.setHorizontalAlignment(JTextField.RIGHT);
firstint = firstint + strings;
}
}
} else if (strings.matches("[+\\-*/]{1}")) {
if (firstint == "") {
if (ans != "") {
firstint += ans+strings;
this.input_text.setText(firstint);
}
if(strings=="-"){
firstint += strings;
this.input_text.setText(input_text.getText()+strings);
}
//JOptionPane.showMessageDialog(null, "请先输入操作数");
} else if (ToPolland.isSymbol(String.valueOf(firstint.charAt(firstint.length() - 1)))&&strings!="-") {
JOptionPane.showMessageDialog(null, "表达式错误");
} else {
this.input_text.setText(input_text.getText() + strings);
firstint = firstint + strings;
System.out.println(firstint);
}
} else if (strings.matches("[()]{1}")) {
if (strings.equals("(")) {
if(firstint==""){
firstint+="(";
this.input_text.setText(firstint);
this.input_text.setHorizontalAlignment(JTextField.RIGHT);
}else if(ToPolland.isNumber(String.valueOf(firstint.charAt(firstint.length()-1)))){
firstint+="*"+strings;
this.input_text.setText(firstint);
}else if(ToPolland.isSymbol(String.valueOf(firstint.charAt(firstint.length()-1)))){
firstint+=strings;this.input_text.setText(firstint);
}
System.out.println(firstint);
} else if (strings.equals(")") && firstint != "") {
if (firstint.charAt(firstint.length() - 1) != '(') {
int count1 = 0, count2 = 1;
for (int i = 0; i < firstint.length(); i++) {
if (firstint.charAt(i) == '(') {
count1++;
}
if (firstint.charAt(i) == ')') {
count2++;
}
}
if (count1 >= count2) {
this.input_text.setText(input_text.getText() + strings);
firstint = firstint + strings;
System.out.println(firstint);
}
}
}
} else if (strings.equals("=")) { //计算结果
try {
System.out.println(firstint);
StringBuilder builder = new StringBuilder();
List<String> list = toPolland(ToPolland.toList(firstint));
list.forEach(builder::append);
System.out.println("算式表达式:" + firstint);
System.out.println("转逆波兰表达式:" + builder);
System.out.println("转逆波兰表达式计算结果:" + firstint + "=" + ToPolland.calculate(list));
ans = String.valueOf(ToPolland.calculate(list));
this.input_text.setText("" + ToPolland.calculate(list));
hitory += firstint + "=" + ToPolland.calculate(list) + "\n";
firstint = "";
} catch (Exception e1) {
JOptionPane.showMessageDialog(null, "表达式错误");
firstint = "";
this.input_text.setText("");
}
} else if (strings.equals("H")) { //查看历史记录
history.setFont(new Font("宋体", Font.BOLD, 20));
this.history.setText(hitory);
} else if (strings.equals("C")) { //清空当前记录
firstint = "";
this.input_text.setText("");
} else if (strings.equals("AC")) { //清空历史记录
firstint = "";
hitory = "";
this.history.setText("");
this.input_text.setText("");
} else if (strings.equals("←") && firstint.length() != 0) { //退格
firstint = firstint.substring(0, firstint.length() - 1);
System.out.println(firstint);
this.input_text.setText("" + firstint.substring(0, firstint.length()));
}
}
}
public static void main(String[] args) {
Calculator carculator = new Calculator();
carculator.setVisible(true);
}
public class ToPolland {
//表达式中存在负数时,后面的逆波兰表达式算法无法得到正确结果,需要补0
public static String tList(String strings) {
String stringBuilder = "";
if(strings.charAt(0)=='-'){//如果第一个字符是‘-',在负号前面补0
stringBuilder+= "0";
}
stringBuilder+=strings.charAt(0); //将第一个‘-'号接到0后面
//如果遇到负号,并且负号前面的符号不是数字,在负号前面补0
for (int i = 1; i < strings.length(); i++) {
if (strings.charAt(i) == '-' && (!isNumber(String.valueOf(strings.charAt(i - 1))))) {
stringBuilder += "0" + strings.charAt(i);
} else stringBuilder += strings.charAt(i);//没有负号则直接拼接
}
return stringBuilder;
}
//将表达式存入list
public static List<String> toList(String strings) {
strings = tList(strings);
if (strings == null || strings.length() <= 0) {
throw new NullPointerException("表达式不能为空!");
}
// 去掉不合法的符号
strings = strings.replaceAll("\\s*|\t|\r|\n", "");
List<String> list = new ArrayList<>();
char[] chars = strings.toCharArray();
String ch="",str="";
for (int i = 0; i < chars.length; i++) {
// 判断是否是数字
if (!Character.isDigit((chars[i]))) {
list.add(String.valueOf(chars[i]));
} else { //如果是数字,就判断下一个是不是数字,如果是就进行组合(循环),然后录入list
do {
ch = String.valueOf(chars[i]); //读取一个字符
str += ch; //进行拼接
i++;
//不是最后一个字符,并且下一个还是数字或者小数点,就进行循环
} while ((i < strings.length()) && ((chars[i] <= 57
&& chars[i] >= 48) || '.' == chars[i]));
list.add(str);//将拼接的字符串录入到list
str = "";i--;
System.out.println(list);//这里一定要将str置位初值
}
}
return list;
}
//转逆波兰表达式
public static List<String> toPolland(List<String> list) {
Stack<String> s1 = new Stack();
List<String> s2 = new ArrayList<>();
// 从左至右扫描中缀表达式;
for (String item : list) {
// 遇到操作数时,将其压s2;
if (Pattern.matches("-?[0-9]+(\\.[0-9]+)?", item)) {
s2.add(item);
}//遇到操作符时,比较其与栈顶的操作符的优先级
if (isSymbol(item)) {
while (s1.size() > 0 && isSymbol(s1.peek()) && priority(item) <= priority(s1.peek())) {
s2.add(s1.pop());
}
s1.push(item);
}
if (item.equals("(")) { //右括号直接入栈
s1.push(item);
}
if (item.equals(")")) { //遇到右括号,将左括号之前的操作符全部出栈
while (!s1.peek().equals("(")) {
s2.add(s1.pop());
}
s1.pop();// 将左边的括号,弹栈
}
}
while (s1.size() > 0) { //将剩余的操作符全部入栈
s2.add(s1.pop());
}
return s2;
}
//逆波兰表达式的计算
public static BigDecimal calculate(List<String> nipollands) {
if (nipollands == null || nipollands.size() <= 1) {
throw new NullPointerException("逆波兰表达式列表不能为空!");
}
Stack<BigDecimal> stack = new Stack();
for (String nipolland : nipollands) {
if (isNumber(nipolland)) { //数字直接入栈
stack.push(new BigDecimal(nipolland));
} else { //遇到操作符取出两个数进行对应的计算,并将计算结果入栈
BigDecimal number1 = stack.pop();
BigDecimal number2 = stack.pop();
BigDecimal result;
switch (nipolland) {
case "+" -> result=number2.add(number1);
case "-" -> result=number2.subtract(number1);
case "*" -> result=number2.multiply(number1);
case "/" -> result=number2.divide(number1, 3,RoundingMode.HALF_UP);
default -> throw new RuntimeException("不合法操作符:" + nipolland);
}
stack.push(result);//遍历字符串后得到的栈顶既为逆波兰表达式计算结果
}
}
return stack.pop();
}
//判断是否为数字
public static boolean isNumber(String str) {
return Pattern.matches("-?[0-9]+(\\.[0-9]+)?", str);
}
//是否是运算符
public static boolean isSymbol(String str) {
return "+-*/".contains(str);
}
//返回运算符的优先级
public static int priority(String value) {
if ("+-".contains(value)) {
return 1;
} else if ("*/".contains(value)) {
return 2;
} else {
throw new RuntimeException("暂不支持操作符:" + value);
}
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程学习网。
本文标题为:Java实现简易计算器(逆波兰表达式)
基础教程推荐
- Java并发编程进阶之线程控制篇 2023-03-07
- springboot自定义starter方法及注解实例 2023-03-31
- Java实现查找文件和替换文件内容 2023-04-06
- ConditionalOnProperty配置swagger不生效问题及解决 2023-01-02
- java基础知识之FileInputStream流的使用 2023-08-11
- JDK数组阻塞队列源码深入分析总结 2023-04-18
- java实现多人聊天系统 2023-05-19
- Java实现线程插队的示例代码 2022-09-03
- Java文件管理操作的知识点整理 2023-05-19
- Java数据结构之对象比较详解 2023-03-07