C/C++——支持括号和自定义运算符的表达式计算器

简介

简单的表达式计算器,输入一个字符串给出计算结果,数字支持小数,符号支持括号“()”和自定义双目运算符(单字符),预定义了+,-,*,/,%,^六种运算符。原理就是中缀表达式string→后缀表达式vector→利用stack计算。

效果

1.测试代码
// 文件名:main.cpp
#include <iostream>
#include "Calculator.h"

using namespace std;

double difference_of_square(double a, double b) {
	// 类型为double(double, double)的函数才能用于注册运算符
    return a * a - b * b;
}

int main() {
	// 新建一个计算器对象
    Calculator cal; 
    // 像函数一样调用计算表达式,答案1.16
    cout << cal("1 + (2 - 3 * 4 / 5) ^ 2") << endl; 
    // 数字中若有多个小数点则第二个点及之后的数字会被忽略(0.5.123.4 => 0.5),答案-0.5
    cout << cal("1 / (4 * 0.5.123.4 - 2*(8^2 % 5 - 2))") << endl; 
    // 除以0会产生NaN
    cout << cal("0 * (1 / 0)") << endl;
    // 注册一个平方差运算符’#‘,优先级为3(高于’*‘,’/‘),运算函数为difference_of_square
    cal.login('#', 3, difference_of_square);
    // 答案0
    cout << cal("3 - ((2 + 3) # 4)^0.5") << endl;
    // 注销幂运算符'^'
    cal.logout('^');
    // 此时遇到’^‘运算符将抛出异常
    try {
        cout << cal("2 ^ 2") << endl;
    }
    catch (runtime_error re) {
        cout << re.what() << endl;
    }
}
2.输出

输出

代码

1.头文件
// 文件名:Calculator.h
#pragma once
#include <iostream>
#include <cmath>
#include <string>
#include <vector>
#include <map>
#include <stack>

class Calculator {
public:
    Calculator();
    void login(char oper, int priory, double(*func)(double, double));
    void logout(char oper);
    double operator()(const std::string& expr);
private:
    std::map<char, int> oper_priorities;
    std::map<char, double(*)(double, double)> oper_funcs;
    double Calculate(const std::vector<std::string>& postfix);
    std::vector<std::string> ToPostfix(const std::string& expr);
    static double add(double a, double b);
    static double sub(double a, double b);
    static double mul(double a, double b);
    static double div(double a, double b);
    static double mod(double a, double b);
    static double pow(double a, double b);
};
2.源文件
// 文件名:Calculator.cpp
#include "Calculator.h"
using namespace std;

Calculator::Calculator() {
	oper_priorities['('] = -1;
	oper_priorities[')'] = -1;
	login('+', 1, add);
	login('-', 1, sub);
	login('*', 2, mul);
	login('/', 2, div);
	login('%', 2, mod);
	login('^', 3, pow);
}

void Calculator::login(char oper, int priory, double(*func)(double, double)) {
	if (oper == '(' || oper == ')') return;
	oper_priorities[oper] = priory;
	if (func != nullptr) oper_funcs[oper] = func;
}

void Calculator::logout(char oper) {
	if (oper == '(' || oper == ')') return;
	oper_priorities.erase(oper);
	oper_funcs.erase(oper);
}

double Calculator::operator()(const string& expr) {
    return Calculate(ToPostfix(expr));
}

double Calculator::Calculate(const vector<string>& postfix) {
    stack<double> nums;
    for (const string& s : postfix) {
        auto it(oper_funcs.find(s[0]));
        if (it == oper_funcs.end()) {
            nums.push(stod(s));
        }
        else {
            double b = nums.top();
            nums.pop();
            double a = nums.top();
            nums.pop();
            nums.push(it->second(a, b));
        }
    }
    return nums.top();
}

vector<string> Calculator::ToPostfix(const string& expr) {
    vector<string> postfix;
    stack<char> opers;
    string num;
    for (char c : expr) {
        if (c == ' ') continue;
        if ('0' <= c && c <= '9' || c == '.') {
            num += c;
            continue;
        }
        if (!num.empty()) {
            postfix.push_back(num);
            num.clear();
        }
        if (c == '(') {
            opers.push(c);
            continue;
        }
        if (c == ')') {
            while (!opers.empty() && opers.top() != '(') {
                postfix.push_back(string(1, opers.top()));
                opers.pop();
            }
            if (opers.empty()) throw runtime_error("Bracket mismatch");
            else opers.pop();
            continue;
        }
        auto it(oper_priorities.find(c));
        if (it != oper_priorities.end()) {
            while (!opers.empty() && it->second < oper_priorities[opers.top()]) {
                postfix.push_back(string(1, opers.top()));
                opers.pop();
            }
            opers.push(c);
            continue;
        }
        throw runtime_error(string("Unknow char: ") + c);
    }
    if (!num.empty()) postfix.push_back(num);
    while (!opers.empty() && opers.top() != '(') {
        postfix.push_back(string(1, opers.top()));
        opers.pop();
    }
    if (!opers.empty()) throw runtime_error("Bracket mismatch");
    return postfix;
}

double Calculator::add(double a, double b) { return a + b; }

double Calculator::sub(double a, double b) { return a - b; }

double Calculator::mul(double a, double b) { return a * b; }

double Calculator::div(double a, double b) {
    if (b == 0) return NAN;
    return a / b;
}

double Calculator::mod(double a, double b) {
    if (b == 0) return NAN;
    return static_cast<int>(a) % static_cast<int>(b);
}

double Calculator::pow(double a, double b) { return std::pow(a, b); }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值