[C ++] Evaluación de expresiones aritméticas (versión fácil de expandir)

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)

Supongo que te gusta

Origin blog.csdn.net/m0_43448982/article/details/89080654
Recomendado
Clasificación