Hay muchos códigos de evaluación de expresiones aritméticas en Internet, pero no son fáciles de expandir y están mal adaptados a varias formas de expresiones, especialmente a la diferencia entre "signo menos" y "signo menos". Pégueme aquí Un código de expresión aritmética escrito por mí. En cuanto al principio de solución, consulte otros blogs en Internet.
//首先我们把运算符都在一个map里注册一下,数值为该运算符的优先级
//这里添加的 $、#、%、e、_ 这些运算符分别指代“对数运算”、“自然对数运算”、“根式运算”、“科学记数法标记符”、“特殊的负号标记符(实际使用时可以仍写‘-’)”
std::map<char, int> mps;
void inti()
{
mps['+'] = 4; mps['-'] = 4;
mps['*'] = 3; mps['/'] = 3;
mps['_'] = 2;
mps['$'] = 1; mps['#'] = 1;
mps['^'] = 0; mps['%'] = 0; mps['e'] = 0;
mps['('] = 16; mps[')'] = 16;
}
Tenga en cuenta que aquí establecemos la precedencia del operador de corchetes en 16, y usted mismo puede entender la razón
//括号匹配,当然觉得不需要可以不写,这里我们可以做一个宏定义
#define CHECK_brackets
bool judge(std::string& value)
{
stack<char> s;
for (int i = 0; i < value.size(); i++)
{
if (value[i] == '(' || value[i] == '[' || value[i] == '{') s.push(value[i]);
else if (value[i] == ')') {
if (s.top() != '(') return false; s.pop(); }
else if (value[i] == ']') {
if (s.top() != '[') return false; s.pop(); }
else if (value[i] == '}') {
if (s.top() != '{') return false; s.pop(); }
}
if (!s.empty()) return false;//这行代码其实可以不要,因为在计算器中,默认会为行尾添加上括号。
return true;
}
Entonces hay una función para el procesamiento de expresiones infijas
//负责删除输入内的空格、TAB等字符,并判断“-”是“负号”还是”减号“,并对错误的符号进行了错误抛出。
std::string delete_space(std::string& value)
{
inti();
#ifdef CHECK_brackets
if (!judge(value)) throw std::runtime_error("brackets error");
#endif
std::string ans, error = "unknown character: ";
int leftbrackets = 0;
for (int i = 0; i < value.size(); i++)
{
if (value[i] == ' ' || value[i] == '\b' || value[i] == '\n') continue;
if (value[i] == '(') leftbrackets++;
else if (value[i] == ')') leftbrackets--;
else if (value[i] == '[') {
leftbrackets++; value[i] = '('; }
else if (value[i] == ']') {
leftbrackets++; value[i] = ')'; }
else if (value[i] == '{') {
leftbrackets++; value[i] = '('; }
else if (value[i] == '}') {
leftbrackets++; value[i] = ')'; }
else if (value[i] == '-' && (i == 0 || ((ans.back() < '0' || ans.back() > '9') && ans.back() != '.' && ans.back() != ')')))
value[i] = '_';//这里把负号与减号区别开来
else if ((value[i] < '0' || value[i] > '9') && !mps.count(value[i]) && value[i] != '.') {
error.push_back(value[i]); throw std::runtime_error(error); }
ans.push_back(value[i]);
}
while (leftbrackets--) ans.push_back(')');
return ans;
}
Luego, la expresión de infijo a sufijo
//将中缀表达式转化为后缀表达式
std::string postfix_expression(std::string& value)
{
std::string ans;
stack<char> s;
bool flag = true;
for (int i = 0; i < value.size(); i++)
{
if ((value[i] <= '9' && value[i] >= '0') || value[i] == '.') ans.push_back(value[i]);
else
{
ans.push_back(' ');
switch (value[i])
{
case '(':
s.push(value[i]);
flag = true;
break;
case ')':
while (!s.empty() && s.top() != '(') {
ans.push_back(s.top()); s.pop(); }
s.pop();
break;
default:
int t = mps[value[i]];
while (!s.empty() && mps[s.top()] <= t) {
ans.push_back(s.top()); s.pop(); }
s.push(value[i]);
break;
}
}
}
while (!s.empty()) {
ans.push_back(s.top()); s.pop(); }
return ans;
}
Luego reservé dos funciones para facilitar la lectura de datos
//单目运算符从这里取数据
void getone(stack<double>& s, double& k)
{
if (!s.empty()) {
k = s.top(); s.pop(); }
else throw std::runtime_error("expression error");
return;
}
//双目运算符从这里取数据
void gettwo(stack<double>& s, double& a, double& b) {
getone(s, b); getone(s, a); }
El último es el cálculo. Por supuesto, llamé a todas las funciones anteriores directamente en esta función, por lo que solo necesito llamar a esta función al final.
//最终计算的函数,直接调用这个函数来完成计算
double calculate(std::string& value)
{
value = delete_space(value);
value = postfix_expression(value);
stack<double> s;
double cur = 0;
bool flag = false;
double dot = 1;
for (int i = 0; i < value.size(); i++)
{
if (value[i] == ' ' && flag){
s.push(cur); cur = 0; flag = false; dot = 1; }
else if (value[i] <= '9' && value[i] >= '0')
{
if (dot != 1) {
cur += dot * (value[i] - '0'); dot *= 0.1; flag = true; }
else {
cur *= 10; cur += value[i] - '0'; flag = true; }
}
else if (value[i] == '.')
{
if (dot == 1) {
dot = 0.1; flag = true; }
else throw std::runtime_error("expression error");
}
else
{
if (flag) {
s.push(cur); cur = 0; flag = false; dot = 1; }
double a, b;
switch (value[i])
{
case '+':
gettwo(s, a, b); s.push(a + b);
break;
case '-':
gettwo(s, a, b); s.push(a - b);
break;
case '*':
gettwo(s, a, b); s.push(a * b);
break;
case '/':
gettwo(s, a, b); s.push(a / b);
break;
case '^':
gettwo(s, a, b); s.push(pow(a, b));
break;
case '%':
gettwo(s, a, b); s.push(pow(b, 1 / a));
break;
case '$':
gettwo(s, a, b); s.push(log(b) / log(a));
break;
case 'e':
gettwo(s, a, b); s.push(a * pow(10, b));
break;
case '_':
getone(s, a); s.push(-a);
break;
case '#':
getone(s, a); s.push(log(a));
break;
default:
break;
}
}
}
if (s.empty()) s.push(cur);
return s.top();
}
Solo necesita ingresar una expresión aritmética de tipo cadena, esta función resolverá y regresará automáticamente, si encuentra un error, también arrojará una descripción del error, puede usar try to test. Finalmente, agregue la prioridad del símbolo de este código
1、括号"("、")"
2、次方运算"^"、根式运算"%"(示例:3%8=2,“%”前为开根号的次数,后为被开根号的数)、科学记数法"e"
3、对数运算"\$"(示例:2$8=3,“\$”前为底数,后为真数,注意不可以使用 e 来表示自然对数的底数,请使用“#”代替“\$“来做对 e 的对数,例如:#2)
4、负号"-"
5、乘法"*"、除法"/"
6、加法"+"、减法"-"
Si desea agregar un símbolo, puede registrar el símbolo en la función inti anterior y agregar el método de operación al interruptor en la función de solución final. (Consulte otros operadores para agregar el método)