/
index.cpp
256 lines (255 loc) · 11.9 KB
/
index.cpp
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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
#include <bits/stdc++.h>
#include <unistd.h>
#include <windows.h>
class Trungto
{
int n; // n là số phần tử của mảng input, mongoac và dongngoac để lưu lại có bao nhiêu dấu mở ngoặc đóng ngoặc
std::string test;
std::stack <std::string> s1;
std::stack <char> s2;
std::string tg, tg2; // Dùng để lưu lại số thập phân để xài
public:
std::string error;
Trungto(){}
Trungto(std::string test){
this->test = test;
this->n = test.length();
}
~Trungto(){}
// Hàm để kiểm tra xem ký tự char c truyền vào có phải là một toán tử không, đồng thời phân chia độ ưu tiên của toán tử
int toantu(char c){
if(c == '*' || c == '/') return 2;
if(c == '+' || c == '-') return 1;
return 0;
}
// Hàm kiểm tra xem ký tự char c truyền vào có phải là một chữ số không
bool chuso(char c){
if(c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || c == '5' || c == '6' || c == '7' || c == '8' || c == '9')
return true;
return false;
}
std::string tinhtoan(std::string a, std::string b, char c){
float x, y, s;
x = atof(a.c_str());
y = atof(b.c_str());
if(c == '+') s = x + y;
if(c == '-') s = y - x;
if(c == '*') s = x * y;
if(c == '/') s = y / x;
a = std::to_string(s);
return a;
}
void instack(){
tg = s1.top(); // Lấy phần tử của đỉnh stack s1
s1.pop(); // Xóa phần tử của đỉnh stack s1
tg2 = s1.top(); // Lấy phần tử của đỉnh stack s1 lần 2
s1.pop(); // Xóa phần tử của đỉnh stack s1 lần 2
s1.push(tinhtoan(tg, tg2, s2.top())); // Chèn vào đỉnh stack s1: tg + - * / tg2
s2.pop(); // Xóa phần tử của đỉnh stack s2
}
std::string lamtron(std::string a, int n){
std::stringstream ss;
int pos = a.find('.');
if(n == 0){
for(int i = 0 ; i < pos; i ++){
ss << a[i];
}
}
else{
for(int i = 0 ; i <= pos + n; i ++){
ss << a[i];
}
}
ss >> a;
return a;
}
bool validate(){
int mongoac = 0, dongngoac = 0;
bool check1;
/* Validate:
Ở giữa:
- Hai toán tử ko được gần nhau như này: *+
- Ngoặc vs số ko được gần nhau như này: 5(, )5
- Hai ngoặc không được như này: (), )(
- Dấu chấm phải nằm giữa 2 số: 9.6
- Số ngoặc mở phải bằng số ngoặc đóng và phải có ngoặc mở trước
- Ngoặc mở phải được thấy trước ngoặc đóng
- Toán tử phải nằm giữa 2 số hoặc nằm sau dấu ), nằm trước dấu (
Ở đầu:
- Chỉ có số và dấu mở ngoặc được phép
Ở cuối:
- Chỉ có số và dấu đóng ngoặc được phép
*/
// Kiểm tra xem ký tự đầu tiên có phải là dấu mở ngoặc hoặc là 1 số không
if(test[0] != '(' && !chuso(test[0])){
error = "Bạn đã viết sai cú pháp, ký tự đầu tiên phải là số hoặc dấu mở ngoặc!";
return false;
}
else{
if(test[0] == '('){
mongoac ++;
}
// Kiểm tra xem ký tự cuối cùng có phải là dấu đóng ngoặc hoặc là 1 số không
if(test[n-1] != ')' && !chuso(test[n-1])){
error = "Bạn đã viết sai cú pháp, ký tự cuối cùng phải là số hoặc dấu đóng ngoặc!";
return false;
}
else{
check1 = false;
for(int i = 1; i < n; i++){
// Kiểm tra xem phần tử mình duyệt có chứa các ký tự khác không được phép không
if(toantu(test[i]) == 0 && test[i] != '(' && test[i] != ')' && test[i] != '.' && !chuso(test[i]) && test[i] != ' '){
error = "Dường như bạn đã nhập sai, những ký tự được hỗ trợ gồm + - * / ( ) . dấu cách và 0 đến 9!";
return false;
}
// Dấu . phải nằm giữa 2 số
if(test[i] == '.'){
if(!chuso(test[i - 1]) || !chuso(test[i + 1])){
error = "Dường như bạn đã viết sai số thập phân, xem lại nhé!";
return false;
}
}
// Hai toán tử không được gần nhau
if(toantu(test[i]) != 0){
if(toantu(test[i - 1]) != 0 || toantu(test[i + 1]) != 0){
error = "Dường như bạn đã viết toán tử liền kề nhau, xem lại nhé!";
return false;
}
}
// Kiểm tra xem có các kiểu cấu trúc dạng này không: 5(, (), )( và tăng giá trị của dấu mở ngoặc lên 1
if(test[i] == '('){
mongoac ++;
if(test[i - 1] == ')' || test[i + 1] == ')' || chuso(test[i - 1])){
error = "Bạn đã viết sai một trong số các cú pháp sau: 5(, (), )(";
return false;
}
}
// Toán tử nằm giữa 2 số hoặc nằm sau dấu ), nằm trước dấu (
if(toantu(test[i]) != 0){
if(test[i - 1] != ')' && !chuso(test[i - 1])){
error = "Dường như bạn đã đặt sai chỗ toán tử, xem lại nhé!";
return false;
}
if(test[i + 1] != '(' && !chuso(test[i + 1])){
error = "Dường như bạn đã đặt sai chỗ toán tử, xem lại nhé!";
return false;
}
}
// Kiểm tra xem có các kiểu cấu trúc dạng này không: )5, (), )( và tăng giá trị của dấu đóng ngoặc lên 1
if(test[i] == ')'){
dongngoac ++;
if(test[i - 1] == '(' || test[i + 1] == '(' || chuso(test[i + 1])){
error = "Bạn đã viết sai một trong số các cú pháp sau: (5, (), )(";
return false;
}
// Kiểm tra xem dấu đóng ngoặc có xuất hiện trước dấu mở ngoặc không
if(dongngoac > mongoac){
error = "Có vấn đề với dấu đóng ngoặc, hãy chắc chắn rằng bạn đã nhập đúng!";
return false;
check1 = true;
}
}
}
// Sau khi duyệt hết phần tử, so sánh dấu đóng và mở ngoặc xem có bằng nhau không
if(dongngoac != mongoac && check1 == false){
error = "Có vấn đề với dấu mở đóng ngoặc, số dấu mở ngoặc khác số dấu đóng ngoặc!";
return false;
}
}
}
return true;
}
std::string start(int tronso){
std::stringstream ss; // Dùng để nối số thập phân
std::string a;
char b; // Dùng để lưu lại toán tử và dấu đóng mở ngoặc để xài
bool check, check2; // Check để kiểm tra xem số thập phân có tồn tại không, check2 để kiểm tra toán tử có tồn tại không
ss.str("");
ss.clear();
check2 = true;
for(int i = 0; i < n; i++){ // Duyệt hết chuỗi
if(test[i] == ' ') continue;
if(!chuso(test[i]) && test[i] != '.'){ // Nếu không phải là chữ số và dấu .
if(ss.rdbuf()->in_avail() == 0){ // Kiểm tra ss có chứa số không
b = test[i]; // b là toán tử hoặc dấu ngoặc
}
else{
b = test[i]; // b là toán tử hoặc dấu ngoặc
check = true;
ss >> a; // a sẽ chứa số thập phân
ss.str(""); // Clear ss
ss.clear();
}
}
else{ // Nếu là toán tử hoặc dấu ngoặc
if(chuso(test[i]) || test[i] == '.'){ // Nếu là chữ số hoặc dấu .
ss << test[i]; // Truyền vào ss
}
if(chuso(test[n - 1]) && i == (n - 1)){
check = true;
check2 = false;
ss >> a;
ss.str("");
ss.clear();
}
else{
continue;
}
}
if(check == true){ // Nếu có giá trị số float được trả về
s1.push(a);
}
if(check2 == true){ // Nếu có giá trị char được trả về
if(b == '(') // Gặp dấu mở ngoặc thì cho vào stack s2
s2.push(b);
if(toantu(b) != 0){
if(!s2.empty()){
while(true){
if(s2.empty()) break;
if(toantu(b) > toantu(s2.top()) || toantu(b) == 0){
break;
}
else{
instack();
}
}
}
s2.push(b);
}
if(b == ')'){
while(true){
if(s2.top() == '('){
s2.pop();
break;
}
else{
instack();
}
}
}
}
check = false;
}
while(!s2.empty()){
instack();
}
return lamtron(s1.top(), tronso);
}
};
int main(){
SetConsoleOutputCP(65001);
std::string bieuthuc = "9.898+8.22*(7.64-(8.2654+9.11)-2.65)*89+655.66";
int sochusosaudauphay = 2;
Trungto T {bieuthuc};
// Nếu cần xác định input có đúng không?
if(T.validate()){
std::cout << T.start(sochusosaudauphay);
}
else
{
std::cout << T.error;
}
// Nếu không cần xác định input mà tính toán luôn
// std::cout << T.start(sochusosaudauphay);
return 0;
}