由于项目需要,实现了一个能处理数学表达式的类,
类主要采用了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;
}