微信小程序之简易计算器

一、介绍

1.中缀表达式

中缀表达式是一种通用的算术或逻辑公式表示方法,操作符以中缀形式处于操作数的中间。中缀表达式是人们常用的算术表示方法。
虽然人的大脑很容易理解与分析中缀表达式,但对计算机来说中缀表达式却是很复杂的,因此计算表达式的值时,通常需要先将中缀表达式转换为前缀或后缀表达式,然后再进行求值。对计算机来说,计算前缀或后缀表达式的值非常简单。

1.后缀表达式

从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 op 栈顶元素),并将结果入栈;重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果。
例:
(1)8+4-62用后缀表达式表示为:
8 4+6 2
-
(2)2*(3+5)-4+7/1用后缀表达式表示为:
3 5+2*7 1/4-+

例如后缀表达式“3 4 + 5 × 6 -”:
(1) 从左至右扫描,将3和4压入堆栈;
(2) 遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素,注意与前缀表达式做比较),计算出3+4的值,得7,再将7入栈;
(3) 将5入栈;
(4) 接下来是×运算符,因此弹出5和7,计算出7×5=35,将35入栈;
(5) 将6入栈;
(6) 最后是-运算符,计算出35-6的值,即29,由此得出最终结果。

二、程序代码

1.代码

app.js配置代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// app.js
App({
onLaunch() {
// 展示本地存储能力
const logs = wx.getStorageSync('logs') || []
logs.unshift(Date.now())
wx.setStorageSync('logs', logs)

// 登录
wx.login({
success: res => {
// 发送 res.code 到后台换取 openId, sessionKey, unionId
}
})
},
globalData: {
userInfo: null
},

calculator:{
express:'', //临时字符串
strList:[], //中缀表达式存储(队列先进先出)
strListP:[], //后缀表达式(队列先进先出)
list:[], //存放运算符的堆栈 (先进后出)
calculate:[] //计算表达式堆栈(先进后出)
}
})

2.逻辑代码

calculator.js代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
// pages/calculator/calculator.js
const app = getApp()
Page({
/**
* 页面的初始数据
*/
data: {
operators: ['AC', 'DEL', '%', '/', '7', '8', '9', '×', '4', '5', '6', '+', '1', '2', '3', '-', '0', '.'],
res: '=',
expression: '0',
},

clearAll() {
this.setData({
expression: '0',
result: ''
})
},

click: function (event) {
const val = event.target.dataset.value;

if (val == 'AC') {
this.clearAll();
} else if (val == 'DEL') {
if (this.data.expression != '0') {
const res = this.data.expression.substr(0, this.data.expression.length - 1);
this.setData({
expression: res
})
}
} else {
var len = this.data.expression.length;
var s = this.data.expression.substring(len - 1, len);
if ((this.checkOperator(s)) && this.checkOperator(val)) {
const res = this.data.expression.substr(0, this.data.expression.length);
this.setData({
expression: res
})
} else {
if ((this.data.expression == '0') && (val == '.')) {
this.setData({
expression: this.data.expression + String(val)
})
} else {
this.setData({
expression: this.data.expression === '0' ? val : this.data.expression + String(val)
})
}
}

}

},

result() {
app.calculator.strList.length = 0;
app.calculator.strListP.length = 0;
app.calculator.list.length = 0;
app.calculator.calculate.length = 0;

this.expressToStrList(this.data.expression);

let tempList = app.calculator.strList;
this.expressToStrListP(tempList);

let tempP = app.calculator.strListP
for (let m in tempP) {
if (this.checkOperator(tempP[m])) {
let op1 = app.calculator.calculate[0];
app.calculator.calculate.shift();
let op2 = app.calculator.calculate[0];
app.calculator.calculate.shift();
app.calculator.calculate.unshift(this.countDetail(op2, tempP[m], op1));
} else {
app.calculator.calculate.unshift(tempP[m])
}
}
this.setData({
result: app.calculator.calculate[0]
});
},

countDetail(num1, operator, num2) {
let result = 0.0;
try {
if (operator == "×") {
result = parseFloat(num1) * parseFloat(num2);
} else if (operator == "/") {
result = parseFloat(num1) / parseFloat(num2);
} else if (operator == "%") {
result = parseFloat(num1) % parseFloat(num2);
} else if (operator == "+") {
result = parseFloat(num1) + parseFloat(num2);
} else {
result = parseFloat(num1) - parseFloat(num2);
}
} catch (error) {

}
return result;
},

expressToStrListP(tempList) {//将中缀表达式集合转变为后缀表达式集合
for (let item in tempList) {
if (this.checkOperator(tempList[item])) {
if (app.calculator.list.length == 0) {
app.calculator.list.unshift(tempList[item]);
} else {
if (this.compaerOperator(app.calculator.list[0], tempList[item])) {
for (let x in app.calculator.list) {
app.calculator.strListP.push(app.calculator.list[x]);
}
app.calculator.list.length = 0;
app.calculator.list.unshift(tempList[item]);
} else {
app.calculator.list.unshift(tempList[item]);
}
}
} else {
app.calculator.strListP.push(tempList[item]);
}
}
if (app.calculator.list.length > 0) {
for (let x in app.calculator.list) {
app.calculator.strListP.push(app.calculator.list[x]);
}
app.calculator.list.length = 0;
}
},

compaerOperator(op1, op2) {
if ((op1 == "%" || op1 == "×" || op1 == "/") && (op2 == "-" || op2 == "+")) {
return true;
} else {
return false;
}
},

expressToStrList(expression) { //将字符串表达式变成中缀队列
let temp = '';
for (let i = 0; i < expression.length; i++) {
if (i == 0 && expression[i] == "-") {
temp = temp + expression[i];
} else {
if (this.checkDigit(expression[i])) {
temp = temp + expression[i];
} else {
if (temp.length > 0) {
if (expression[i] == ".") {
temp = temp + expression[i];
} else {
app.calculator.strList.push(parseFloat(temp));
temp = '';
app.calculator.strList.push(expression[i]);
}
} else {
temp = temp + expression[i];
}
}
}
}
if (temp.length > 0 && this.checkDigit(temp.substring(temp.length - 1))) {
app.calculator.strList.push(parseFloat(temp));
temp = '';
}
},

//判断是否是运算符
checkOperator(input) {
if (input == "-" || input == "+" || input == "/" || input == "%" || input == "×") {
return true;
} else {
return false;
}
},

//判断是否是数字
checkDigit(input) {
if ((/^[0-9]*$/.test(input))) {
return true;
} else {
return false;
}
},
})

3.界面代码

calculator.js代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!--pages/calculator/calculator.wxml-->
<view class="contaniner">
<view class="displayer">
<view class="text">{{expression}}</view>
<view class="result">={{result}}</view>
</view>
<view class="btnArea">
<block wx:for="{{operators}}">
<view class="btn" data-value="{{item}}" capture-bind:tap="click">{{item}}</view>
</block>
<view class="btn btn1" data-value="{{res}}" bindtap="result">{{res}}</view>
</view>
</view>

4.样式代码

calculator.js代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/* pages/calculator/calculator.wxss */
.container1{
width: 100%;
height: 100%;
}

.displayer{
border: 1px solid #f1f3f3;
width: 100%;
height: 602
rpx;
font-size: 45rpx;
background-color: rgba(241, 243, 243, 1.0);
}
.btnArea{
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
padding: 3rpx;
margin: 0;
background-color: rgb(241, 243, 243);
}
.btn{
width: 185rpx;
display: flex;
align-items: center;
height: 120rpx;
justify-content: center;
border: 1rpx solid #e8eaeb;
color: black;
background-color: #F7F8F9;
}
.btn1{
width: 370rpx;
}
.text{
width: 100%;
height: 10%;
text-align: right;
margin-top: 470rpx;
background-color: rgba(241, 243, 243, 1.0);
position: absolute;
word-break: break-word;
}

.result{
width: 100%;
height: 58rpx;
text-align: right;
margin-top: 530rpx;
background-color: rgba(241, 243, 243, 1.0);
position: absolute;
word-break: break-word;
}

三.程序截图

四.总结

使用数组来实现堆栈,然后将表达式转为中缀表达式,再转成后缀表达式,利用堆栈实现计算。