数学表达式处理类Calculator

由于项目需要,实现了一个能处理数学表达式的类,
类主要采用了Reverse Polish Notation(逆波兰表达式)完成,写成了模版类,发出来分享一下。
有些地方的代码,实现的自我感觉不太好,但一时又没有找到更简洁的方法。

欢迎拍砖,提供改进意见,共同提高。有需要的同学也可以直接拿来用

特点:支持诸如1M,1G等大小,例如可写出表达式1K+2M*2+1G等

// Copyright (c) 2011, XXX Inc.
// 2011-10-11
// pecywang

#ifndef _CALCULATOR_H_
#define _CALCULATOR_H_

#include <stack>

typedef signed __int32    int32_t;
typedef unsigned __int32  uint32_t;
typedef signed __int64    int64_t;
typedef unsigned __int64  uint64_t;

template<typename T>
class Calculator {
    struct ExprElem {
        bool is_digit;  // 数字or运算符
        char symbol;
        T    value;

        explicit ExprElem(char c) {
            is_digit = false;
            symbol = c;
        }

        explicit ExprElem(T val) {
            is_digit = true;
            value = val;
        }
    };
public:
    explicit Calculator(const char* expression);
    explicit Calculator(const std::string& expression);
    ~Calculator(){};

    bool Value(T* val);

private:
    bool ExprToRPN();     // 正常表达式->逆波兰式(Reverse Polish Notation)
    bool ReverseRPN();    // 反转RPN,为了后续的计算值
    bool RPNToValue();    // 计算RPN
    int32_t  SymbolPriority (char s);  // 运算符优先级
    uint64_t UnitSize(char u);       // 单位代表的值,如'M'=1024*1024

private:
    T m_result;
    const char*  m_expression;
    std::stack<char>     m_symbol;   // 保存运算符
    std::stack<ExprElem> m_expr;     // 保存rpn表达式
};

template<typename T>
Calculator<T>::Calculator(const char* expression) {
    assert(NULL != expression);
    m_expression = expression;
}

template<typename T>
Calculator<T>::Calculator(const std::string& expression) {
    assert(expression.length() > 0);
    m_expression = expression.c_str();
}

template<typename T>
bool Calculator<T>::Value(T* val) {
    assert(NULL != val);
    if (!ExprToRPN()) return false;
    if (!ReverseRPN()) return false;
    if (!RPNToValue()) return false;
    *val = m_result;
    return true;
}

#define valid_units(c) (c == 'b' || c == 'k' || c == 'm' || c == 'g' || c == 't')
#define valid_digit(c) ((c >= '0' && c <= '9') || valid_units(c))
#define valid_expr(c) (valid_digit(c) || c == '+' || c == '-' || c =='*' || c == '/' || c == '(' || c == ')')
template<typename T>
bool Calculator<T>::ExprToRPN() {
    while (*m_expression != '\0') {
        char c = *m_expression;
        c = tolower(c);
        if (!valid_expr(c)) return false;
        switch (c) 
        {
        case '(':
            m_symbol.push(c);
            break;
        case ')':
            {
                bool is_error = true;
                while (!m_symbol.empty()) {
                    char cur = m_symbol.top();
                    m_symbol.pop();
                    if (cur == '(') {
                        is_error = false;
                        break;
                    } else {
                        ExprElem ele(cur);
                        m_expr.push(ele);
                    }
                }
                if (is_error) return false; // lack '('
            }
            break;
        case '-':
            // 兼容负号'-',补0
            {
                char pre = tolower(*(m_expression-1));
                if (pre == '-') return false;   // unsupport '--'
                if (m_expr.empty() || !valid_digit(pre)) {
                    m_expr.push(ExprElem((T)0));
                }
            }
        case '+':
        case '*':
        case '/':
            if (!m_symbol.empty() && SymbolPriority(c) <= SymbolPriority(m_symbol.top())) { // 优先级小于栈顶的
                ExprElem ele(m_symbol.top());
                m_expr.push(ele);
                m_symbol.pop();
            }
            m_symbol.push(c);
            break;
        default:
            if (c >= '0' && c <= '9') {
                ++m_expression;
                T v = c - '0';
                char next = tolower(*m_expression);
                while (valid_digit(next)) {
                    if (valid_units(next)) {
                        v = UnitSize(next)*v;
                    } else {
                        v = v*10 + next - '0';
                    }
                    next = tolower(*(++m_expression));
                }
                ExprElem ele(v);
                m_expr.push(ele);
                continue;
            }
            return false; // ERROR char
        }
        ++m_expression;
    }
    while (!m_symbol.empty()) {
        char s = m_symbol.top();
        if (s == '(') return false; // ERROR,must can't has '(' left
        m_expr.push(ExprElem(s));
        m_symbol.pop();
    }
    return true;
}

template<typename T>
bool Calculator<T>::RPNToValue() {
    stack<T> val_stack;
    if (m_expr.size() == 1 && m_expr.top().is_digit) {
        m_result = m_expr.top().value;
        return true;
    }

    if (m_expr.size() < 2) return false;
    // 第一次入栈2个
    ExprElem ele = m_expr.top();
    if (!ele.is_digit) return false;
    val_stack.push(ele.value);
    m_expr.pop();

    ele = m_expr.top();
    if (!ele.is_digit) return false;
    val_stack.push(ele.value);
    m_expr.pop();

    while (!m_expr.empty()) {
        ele = m_expr.top();
        m_expr.pop();
        if (ele.is_digit) {
            val_stack.push(ele.value);
        } else {
            if (val_stack.size() < 2) return false;
            T d1 = val_stack.top();
            val_stack.pop();
            T d2 = val_stack.top();
            val_stack.pop();
            switch(ele.symbol) 
            {
            case '+':
                val_stack.push(d2+d1);
                break;
            case '-':
                val_stack.push(d2-d1);
                break;
            case '*':
                val_stack.push(d2*d1);
                break;
            case '/':
                assert(d1 != 0);
                val_stack.push(d2/d1);
                break;
            default:
                return false;
            }
        }
    }
    if (val_stack.size() != 1) return false;
    m_result = val_stack.top();
    return true;
}

template<typename T>
bool Calculator<T>::ReverseRPN() {
    stack<ExprElem> temp;
    while(!m_expr.empty()) {
        ExprElem& ele = m_expr.top();
        m_expr.pop();
        temp.push(ele);
    }
    m_expr = temp;
    return true;
}

template<typename T>
int Calculator<T>::SymbolPriority (char s) {
    if (s == '+' || s == '-') return 0;
    if (s == '*' || s == '/') return 1;
    return -1; // '(' etc.
}

template<typename T>
uint64_t Calculator<T>::UnitSize(char u) {
    uint64_t sz = 1;
    switch(u) {
        case 'b':
            break;;
        case 'k':
            sz = sz<<10;
            break;
        case 'm':
            sz = sz<<20;
            break;
        case 'g':
            sz = sz<<30;
            break;
        case 't':
            sz = sz<<40;
            break;
    }
    return sz;
}

#endif//_CALCULATOR_H_

测试代码:

int main () {
    uint64_t val = 0;
    Calculator<uint64_t> c0("(1*2)+3");
    assert(c0.Value(&val));
    assert(val == 5);
    
    Calculator<uint64_t> c1("1+(2+3)");
    assert(c1.Value(&val));
    assert(val == 6);

    Calculator<uint64_t> c2("1+2+(3)");
    assert(c2.Value(&val));
    assert(val == 6);

    Calculator<uint64_t> c3("1*2+3");
    assert(c3.Value(&val));
    assert(val == 5);

    Calculator<uint64_t> c4("1*(2+3)");
    assert(c4.Value(&val));
    assert(val == 5);

    Calculator<uint64_t> c5("1+2*3");
    assert(c5.Value(&val));
    assert(val == 7);

    Calculator<uint64_t> c6("1+(2*1+3)");
    assert(c6.Value(&val));
    assert(val == 6);

    Calculator<uint64_t> c7("(1+2)*3");
    assert(c7.Value(&val));
    assert(val == 9);

    Calculator<uint64_t> c8("(1)*3");
    assert(c8.Value(&val));
    assert(val == 3);

    Calculator<uint64_t> c9("-1+2");
    assert(c9.Value(&val));
    assert(val == 1);

    Calculator<uint64_t> c10("(-1)+2");
    assert(c10.Value(&val));
    assert(val == 1);

    Calculator<uint64_t> c11("2+(-1)");
    assert(c11.Value(&val));
    assert(val == 1);

    Calculator<uint64_t> c12("(-1)");
    assert(c12.Value(&val));
    assert(val == -1);

    Calculator<uint64_t> c13("-1");
    assert(c13.Value(&val));
    assert(val == -1);

    Calculator<uint64_t> c14("0*(-1)");
    assert(c14.Value(&val));
    assert(val == 0);

    Calculator<uint64_t> c15("1*-1");
    assert(c15.Value(&val));
    assert(val == -1);

    Calculator<uint64_t> c16("1+(2");
    assert(c16.Value(&val) == false);

    Calculator<uint64_t> c17("1+2)");
    assert(c17.Value(&val) == false);

    Calculator<uint64_t> c18("1++2");
    assert(c18.Value(&val) == false);

    Calculator<uint64_t> c19("1+2++3");
    assert(c19.Value(&val) == false);

    Calculator<uint64_t> c20("--1+2");
    assert(c20.Value(&val) == false);

    Calculator<uint64_t> c21("++1+2");
    assert(c21.Value(&val) == false);

    Calculator<uint64_t> c22("++1**2");
    assert(c21.Value(&val) == false);

    Calculator<uint64_t> c23("1+/2");
    assert(c23.Value(&val) == false);

    //Calculator<uint64_t> c24("1/(1-1)+2");
    //assert(c24.Value(&val) == false);

    Calculator<uint64_t> c25("1M=1");
    assert(c25.Value(&val) == false);

    Calculator<uint64_t> c26("abasd3546765+-*/=1");
    assert(c26.Value(&val) == false);

    Calculator<uint64_t> c27("1k+1");
    assert(c27.Value(&val));
    assert(val == 1025);

    Calculator<uint64_t> c28("1k-1");
    assert(c28.Value(&val));
    assert(val == 1023);

    Calculator<uint64_t> c29("k-1");
    assert(c29.Value(&val) == false);

    Calculator<uint64_t> c30("1K*2");
    assert(c30.Value(&val));
    assert(val == 2048);

    Calculator<uint64_t> c31("1K*2-1K");
    assert(c31.Value(&val));
    assert(val == 1024);

    Calculator<uint64_t> c32("1*K");
    assert(c32.Value(&val) == false);

    Calculator<uint64_t> c33("1M-2K");
    assert(c33.Value(&val));
    assert(val == 1046528);

    Calculator<uint64_t> c34("2*5T");
    assert(c34.Value(&val));
    assert(val == 10995116277760);

    Calculator<uint64_t> c35("1K");
    assert(c35.Value(&val));
    assert(val == 1024);

    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值