zoukankan      html  css  js  c++  java
  • 对表达式进行空白符预处理

    对表达式进行空白符预处理

             前面我们关于中缀表达式、后缀表达式的输入默认是按照操作符和操作数之间是有空白符区分的,所谓的空白符即为空格或者制表符,不包括换行符。

    // 表达式中操作符和操作数之间默认有空白符
    void get_infix(vector<string>& inf)
    {
        inf.clear();
        string line;
        getline(cin, line);
        istringstream sin(line);
        string tmp;
        while (sin >> tmp)
        {
            inf.push_back(tmp);
        }
    }

             我们这里针对输入表达式不严格规定操作数和操作符之间有空白符,而是对输入的表达式做一个预处理,对输入的表达式中的操作符两端都加上空白符,然后进行分析操作。

             我们结合前面《字符串替换》里的批量替换做空白符预处理,具体程序如下:

    // 对表达式进行空白符预处理
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <string>
    #include <stack>
    #include <map>
    using namespace std;
    
    string& replace_all_distinct(string& str, const string& src, const string& des)
    {
        for (string::size_type i = 0; i != string::npos; i += des.size())
        {
            i = str.find(src, i);
            if (i != string::npos)
            {
                str.replace(i, src.size(), des);
            }
            else
            {
                break;
            }
        }
        return str;
    }
    
    string& n_replace(string& str, const vector<string>& src, const vector<string>& des)
    {
        assert(src.size() > 0 && src.size() == des.size());
        for (vector<string>::size_type i = 0; i != src.size(); ++i)
        {
            replace_all_distinct(str, src[i], des[i]);
        }
        return str;
    }
    
    void get_infix(vector<string>& inf, const vector<string>& src, const vector<string>& des)
    {
        inf.clear();
        string line;
        getline(cin, line);
        
        n_replace(line, src, des);
        
        istringstream sin(line);
        string tmp;
        while (sin >> tmp)
        {
            inf.push_back(tmp);
        }
    }
    
    void show(const vector<string>& hs)
    {
        for (vector<string>::size_type i = 0; i != hs.size(); ++i)
        {
            cout << hs[i] << ' ';
        }
        cout << endl;
    }
    
    void init_op(map<string, int>& ops)
    {
        ops.clear();
        ops["+"] = 100;
        ops["-"] = 100;
        ops["*"] = 200;
        ops["/"] = 200;
        ops["("] = 1000;
        ops[")"] = 0;
    }
    
    bool is_operator(const string& hs, const map<string, int>& ops)
    {
        map<string, int>::const_iterator cit = ops.find(hs);
        if (cit != ops.end())
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    
    void in2post(const vector<string>& inf, vector<string>& postf, map<string, int>& ops)
    {
        postf.clear();
        stack<string> op_st;
        for (vector<string>::size_type i = 0; i != inf.size(); ++i)
        {
            if (!is_operator(inf[i], ops))
            {
                postf.push_back(inf[i]);
            }
            else
            {
                if (inf[i] == "(")
                {
                    op_st.push(inf[i]);
                }
                else if (inf[i] == ")")
                {
                    while (!op_st.empty())
                    {
                        if (op_st.top() == "(")
                        {
                            op_st.pop();
                        }
                        else
                        {
                            postf.push_back(op_st.top());
                            op_st.pop();
                        }
                    }
                }
                else // 若为其他运算符
                {
                    if (op_st.empty()) // 若为空栈,则直接入栈
                    {
                        op_st.push(inf[i]);
                    }
                    else
                    {
                        if (ops[inf[i]] > ops[op_st.top()])
                        {
                            // 如果当前操作符优先级高于站定操作符优先级
                            // 则直接入栈
                            op_st.push(inf[i]);
                        }
                        else
                        {
                            // 否则弹出栈中优先级大于等于当前操作符优先级
                            // 的操作符,并最后将当前操作符压栈
                            while (!op_st.empty() && ops[op_st.top()] >= ops[inf[i]] && op_st.top() != "(")
                            {
                                /* 等价于 && op_st.top != "("
                                if (op_st.top() == "(")
                                {
                                    // 如果当前栈顶操作符为 "("
                                    // 则终止操作,继续保留 "(" 的栈顶位置
                                    break;
                                }
                                */
                                postf.push_back(op_st.top());
                                op_st.pop();
                            }
                            op_st.push(inf[i]);
                        }
                    }
                }
            }
        }
        while (!op_st.empty())
        {
            postf.push_back(op_st.top());
            op_st.pop();
        }
    }
    
    double cal_post(const vector<string>& postf, const map<string, int>& ops)
    {
        stack<double> or_st;
        double operand = 0.0, a = 0.0, b = 0.0, c = 0.0;
        for (vector<string>::size_type i = 0; i != postf.size(); ++i)
        {
            if (!is_operator(postf[i], ops))
            {
                operand = static_cast<double>(atof(postf[i].c_str()));
                or_st.push(operand);
            }
            else
            {
                switch (postf[i][0])
                {
                case '+':
                    b = or_st.top();
                    or_st.pop();
                    a = or_st.top();
                    or_st.pop();
                    c = a + b;
                    or_st.push(c);
                    break;
                case '-':
                    b = or_st.top();
                    or_st.pop();
                    a = or_st.top();
                    or_st.pop();
                    c = a - b;
                    or_st.push(c);
                    break;
                case '*':
                    b = or_st.top();
                    or_st.pop();
                    a = or_st.top();
                    or_st.pop();
                    c = a * b;
                    or_st.push(c);
                    break;
                case '/':
                    b = or_st.top();
                    or_st.pop();
                    a = or_st.top();
                    or_st.pop();
                    c = a / b;
                    or_st.push(c);
                    break;
                default:
                    break;
                }
            }
        }
        if (or_st.size() == 1)
        {
            return or_st.top();
        }
        else
        {
            return -10000000000000.0;
        }
    }
    
    void init_src_des(vector<string>& src, vector<string>& des)
    {
        src.push_back("+");
        src.push_back("-");
        src.push_back("*");
        src.push_back("/");
        src.push_back("(");
        src.push_back(")");
        
        des.push_back(" + ");
        des.push_back(" - ");
        des.push_back(" * ");
        des.push_back(" / ");
        des.push_back(" ( ");
        des.push_back(" ) ");
    }
    
    int main()
    {
        map<string, int> ops;
        init_op(ops);
        vector<string> inf, postf;
        
        vector<string> src, des;
        init_src_des(src, des);
    
    
        while (1)
        {
            get_infix(inf, src, des);
            // show(inf);
            
            in2post(inf, postf, ops);
            show(postf);
            
            double ret = cal_post(postf, ops);
            cout << ret << endl << endl;
        }
        
        system("PAUSE");
        return 0;
    }

             通过对表达式进行空白符预处理,我们避免了词法分析的过程,空白符预处理后,我们利用istringstream字符串流进行输入。这是一种技巧性处理,后续我们会采用词法分析来处理这个过程。

             进行空白符预处理,可以省去输入过程中必须有空白符的限制,使得输入更为随意方便。

  • 相关阅读:
    常见的Mysql十款高可用方案
    01 . OpenResty简介部署,优缺点,压测,适用场景及用Lua实现服务灰度发布
    08 . Jenkins之SpringCloud微服务+Vue+Docker持续集成
    TomcatAJP文件包含漏洞及线上修复漏洞
    Nginx升级加固SSL/TLS协议信息泄露漏洞(CVE-2016-2183)和HTTP服务器的缺省banner漏洞
    03 . Go开发一个日志平台之Elasticsearch使用及kafka消费消息发送到Elasticsearch
    关于本博客皮肤样式配置
    01 . etcd简介原理,应用场景及部署,简单使用
    Spring Cloud Config
    Spring Cloud Gateway
  • 原文地址:https://www.cnblogs.com/unixfy/p/3200342.html
Copyright © 2011-2022 走看看