#include #include #include 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 s1; std::stack 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; }