本文介绍了一种使用字符串替换的方法来计算数学表达式的值。相对于使用栈的方式,这种方法效率较低。这种计算器支持带括号的四则运算。
仅支持四则运算和括号的计算器
这部分代码实现了一个简单的计算器,它可以处理带有括号的四则运算表达式,并输出正确的计算结果;如果表达式输入有误或出现了分母为零等情况将返回nan
。代码如下:
#include <string>
#include <vector>
#include <math.h>
using namespace std;
// 仅支持四则运算的计算器
double _cal(string s)
{
string s1;
string::iterator a, b, i; // a记录'(',b记录')'
string::size_type n = 0;
int l;
if (false)
F:
s.replace(a, i + 1, to_string(_cal(string(a + 1, i))).c_str()); // 递归计算括号
R:
i = s.begin();
while (i < s.end())
{
if (*i == ' ' || *i == '\t')
{
s.erase(i);
goto R;
}
if (*i == '(')
{
if (!n++)
a = i;
}
else if (*i == ')')
{
if (!--n)
goto F;
}
else if (*i != '\0' && *i != '.' && *i != 'e' && *i != '*' && *i != '-' && *i != '+' && *i != '/' && (*i < '0' || *i > '9') || (*i == '/' && *(i + 1) == '0' && *(i + 2) != '.'))
return NAN; // 不是数学表达式
++i;
}
if (n)
return NAN; // 左括号个数不等于右括号个数
vector<string::size_type> u;
/* k用作bool数组
* 第一位表示第一个数字的正负性
* 第二位表示第二个数字的正负性
* 第三位表示第一个数字是否为字符串首个数字
*/
unsigned char k('\0');
// 计算乘除
for (b = a = s.begin(); a < s.end(); ++a)
if (*a == '*' || *a == '/')
u.push_back(a - b);
while (u.size())
{
i = a = b = s.begin() + u[0];
while ((*--b >= '0' && *b <= '9') || *b == '.' || *b == 'e')
if (b == s.begin())
{
k = 4;
goto G;
}
// n记录第一个数字的首位的位置
k += *b == '-';
if (*b == '-')
n = b - s.begin();
else
n = ++b - s.begin();
G:
double t = stod(string(b, a++));
do
if (++a == s.end())
break;
while ((*a >= '0' && *a <= '9') || *a == '.' || *a == 'e');
double w = stod(string(i + 1, a));
k += (w < 0) * 2;
if (*i == '*')
{
l = (s1 = to_string(t * w)).size() - (a - b);
s.replace(b, a, s1.c_str());
}
else if (w)
{
l = (s1 = to_string(t / w)).size() - (a - b);
s.replace(b, a, s1.c_str());
}
else
return NAN; // 除数为0
switch (k)
{
case 2:
s.erase(s.begin() + n - 1);
break; // 删除-号前的+
case 3:
s.insert(s.begin() + n, '+'); // 在计算结果之前加一个+
}
u.erase(u.begin());
for (auto &q : u)
q += l;
}
// 计算加减
H:
for (a = (b = s.begin()) + 1; a < s.end(); ++a)
if (*a == '+')
{
if (*(a + 1) == '-' || *(a + 1) == '+')
{
s.erase(a);
goto H;
}
u.push_back(a - b);
}
else if (*a == '-')
{
if (*(a + 1) == '-')
{
s.replace(a, a + 2, "+");
goto H;
}
else if (*(a + 1) == '+')
{
s.erase(a + 1);
goto H;
}
u.push_back(a - b);
}
else if(*a=='e'||*a=='E')
if(*(a+1)=='-')
++a;
while (u.size())
{
i = a = (b = s.begin()) + u[0];
double t = stod(string(b, a++));
do
if (++a == s.end())
break;
while ((*a >= '0' && *a <= '9') || *a == '.' || *a == 'e');
if (*i++ == '+')
l = (s1 = to_string(t + stod(string(i, a)))).size() - (a - b);
else
l = (s1 = to_string(t - stod(string(i, a)))).size() - (a - b);
s.replace(b, a, s1.c_str());
u.erase(u.begin());
for (auto &q : u)
q += l;
}
return stod(s);
}
支持部分常用函数的计算器
实际使用中,我们可能会遇到诸如sin
、exp
、log
等函数,这部分代码在基础计算器的基础上添加了对这些函数的支持。
/*
* 计算器
* 计算字符串s代表的值
* 支持的函数:sqrt,sin,log,exp,pow,abs,cos,tan,asin,acos,atan
* 支持无理数pi,但不支持e(e已经用作科学计数法的表示),可以用exp(1)表示e
*/
double calStr(string s)
{
if(s.empty())return 0;
string::iterator i(s.begin());
do
switch (*i)
{
case 's':
{
string::iterator j(i);
if (*++j == 'i')
{
if (*++j != 'n')
return NAN;
if (*++j != '(')
return NAN;
string::iterator k(++j);
string::size_type n = 1;
if (*k == '(')
++n;
else if (*k == ')')
return NAN;
while (++k != s.end())
switch (*k)
{
case '(':
++n;
break;
case ')':
if (!--n)
return calStr(s.replace(i, k + 1, to_string(sin(calStr(string(j, k))))));
}
return NAN;
}
if (*j != 'q')
return NAN;
if (*++j != 'r')
return NAN;
if (*++j != 't')
return NAN;
if (*++j != '(')
return NAN;
string::iterator k(++j);
string::size_type n = 1;
if (*k == '(')
++n;
else if (*k == ')')
return NAN;
while (++k != s.end())
switch (*k)
{
case '(':
++n;
break;
case ')':
if (!--n)
return calStr(s.replace(i, k + 1, to_string(sqrt(calStr(string(j, k))))));
}
return NAN;
}
case 'l':
{
string::iterator j(i);
if (*++j != 'o')
return NAN;
if (*++j != 'g')
return NAN;
if (*++j != '(')
return NAN;
string::iterator k(++j);
string::size_type n = 1;
if (*k == '(')
++n;
else if (*k == ')')
return NAN;
while (++k != s.end())
switch (*k)
{
case '(':
++n;
break;
case ')':
if (!--n)
return calStr(s.replace(i, k + 1, to_string(log(calStr(string(j, k))))));
}
return NAN;
}
case 'e':
{
string::iterator j(i);
if (*++j != 'x')
continue;
if (*++j != 'p')
return NAN;
if (*++j != '(')
return NAN;
string::iterator k(++j);
string::size_type n = 1;
if (*k == '(')
++n;
else if (*k == ')')
return NAN;
while (++k != s.end())
switch (*k)
{
case '(':
++n;
break;
case ')':
if (!--n)
return calStr(s.replace(i, k + 1, to_string(exp(calStr(string(j, k))))));
}
return NAN;
}
case 'p':
{
string::iterator j(i);
if (*++j != 'o')
{
if (*j == 'i')
return calStr(s.replace(i, ++j, "3.1415926535897932384626433832795"));
return NAN;
}
if (*++j != 'w')
return NAN;
if (*++j != '(')
return NAN;
string::iterator k(++j), x;
string::size_type n = 1;
if (*k == '(')
++n;
else if (*k == ')')
return NAN;
while (++k != s.end())
switch (*k)
{
case ',':
x = k;
break;
case '(':
++n;
break;
case ')':
if (!--n)
return calStr(s.replace(i, k + 1, to_string(pow(calStr(string(j, x)), calStr(string(x + 1, k))))));
}
return NAN;
}
case 'c':
{
string::iterator j(i);
if (*++j != 'o')
return NAN;
if (*++j != 's')
return NAN;
if (*++j != '(')
return NAN;
string::iterator k(++j);
string::size_type n = 1;
if (*k == '(')
++n;
else if (*k == ')')
return NAN;
while (++k != s.end())
switch (*k)
{
case '(':
++n;
break;
case ')':
if (!--n)
return calStr(s.replace(i, k + 1, to_string(cos(calStr(string(j, k))))));
}
return NAN;
}
case 't':
{
string::iterator j(i);
if (*++j != 'a')
return NAN;
if (*++j != 'n')
return NAN;
if (*++j != '(')
return NAN;
string::iterator k(++j);
string::size_type n = 1;
if (*k == '(')
++n;
else if (*k == ')')
return NAN;
while (++k != s.end())
switch (*k)
{
case '(':
++n;
break;
case ')':
if (!--n)
return calStr(s.replace(i, k + 1, to_string(tan(calStr(string(j, k))))));
}
return NAN;
}
case 'a':
{
string::iterator j(i);
switch (*++j)
{
case 's':
{
if (*++j != 'i')
return NAN;
if (*++j != 'n')
return NAN;
if (*++j != '(')
return NAN;
string::iterator k(++j);
string::size_type n = 1;
if (*k == '(')
++n;
else if (*k == ')')
return NAN;
while (++k != s.end())
switch (*k)
{
case '(':
++n;
break;
case ')':
if (!--n)
return calStr(s.replace(i, k + 1, to_string(asin(calStr(string(j, k))))));
}
return NAN;
}
case 'c':
{
if (*++j != 'o')
return NAN;
if (*++j != 's')
return NAN;
if (*++j != '(')
return NAN;
string::iterator k(++j);
string::size_type n = 1;
if (*k == '(')
++n;
else if (*k == ')')
return NAN;
while (++k != s.end())
switch (*k)
{
case '(':
++n;
break;
case ')':
if (!--n)
return calStr(s.replace(i, k + 1, to_string(acos(calStr(string(j, k))))));
}
return NAN;
}
case 't':
{
if (*++j != 'a')
return NAN;
if (*++j != 'n')
return NAN;
if (*++j != '(')
return NAN;
string::iterator k(++j);
string::size_type n = 1;
if (*k == '(')
++n;
else if (*k == ')')
return NAN;
while (++k != s.end())
switch (*k)
{
case '(':
++n;
break;
case ')':
if (!--n)
return calStr(s.replace(i, k + 1, to_string(atan(calStr(string(j, k))))));
}
return NAN;
}
}
if (*j != 'b')
return NAN;
if (*++j != 's')
return NAN;
if (*++j != '(')
return NAN;
string::iterator k(++j);
string::size_type n = 1;
if (*k == '(')
++n;
else if (*k == ')')
return NAN;
while (++k != s.end())
switch (*k)
{
case '(':
++n;
break;
case ')':
if (!--n)
return calStr(s.replace(i, k + 1, to_string(abs(calStr(string(j, k))))));
}
return NAN;
}
}
while (++i != s.end());
return _cal(s);
}
支持带未知数的函数表达式
若表达式中包含未知数x
,可以使用如下函数来计算:
//在表达式中带有x
double calStr_x(string s,const double& x)
{
for(auto p(s.begin());p!=s.end();++p)
if(*p=='x')
if(p==s.begin()||p+1==s.end()||*(p-1)!='e'||*(p+1)!='p')
return calStr_x(s.replace(p,p+1,to_string(x)),x);
return calStr(s);
}