c++ regex,传递等价的字符串参数,但接收不同的输出

c++ regex, passing equivalent string parameters, but receiving different outputs

本文关键字:输出 参数 字符串 c++ regex      更新时间:2023-10-16

我们收到一个非常不寻常的错误。我们的程序尝试使用正则表达式和递归计算导数。

从我们的文件输入,我们使用regex来确定我们需要应用的派生规则。使用smatch,我们能够解析字符串方程的不同部分。

程序试图计算"(x^2)+(x)"的导数时出现错误。Smatch从这个方程中解析"x^2"answers"x",并使用这两个字符串作为参数递归地调用导数函数。然而,我们的输出缺少x的导数。

输入:

(x^2)+(x)

调用:

return derivative(s[1].str()) + "+" + derivative(s[2].str());
输出:

2x^1*1+

然而,如果我们传递:

return derivative(s[1].str()) + "+" + derivative("x");

则输出为:

2x^1*1+1

我们也检查了if (s[2].str() == "x"),这是真的。为什么我们从相同的输入得到不同的输出?

Equations.txt:

7
x
5x
x^3
(x^2)+(x)

main.cpp:

#include <iostream>
#include <fstream>
#include <cmath>
#include <queue>
#include <stack>
#include <regex>
#include <vector>
#include <iterator>
#include <map>
#include <string>
using namespace std;
/*****************************************************************/
class ReadFile
{
private:
    ifstream infile;
    queue<string> input;
public:
    ReadFile(string filename)
    {
        infile.open(filename);
        if(!infile)
            cerr << "Unable to open filen";
        string temp;
        while(!infile.eof())
        {
            getline(infile, temp);
            input.push(temp);
        }
    }
    string getFront()
    {
        string temp = input.front();
        input.pop();
        return temp;
    }
    bool isEmpty() { return input.empty(); }
};
/*****************************************************************/
class Simplifier
{
private:
    string exp;
public:
    Simplifier(string ex): exp(ex) {}
};
/*****************************************************************/

class ExpressionAnalyzer
{
    string expression;
    map<string, regex> rules;
    smatch s;
public:
    ExpressionAnalyzer()
    {
        rules["con"] = "([[:d:]]+)";
        rules["xxx"] = "(x|\(x\))";
        rules["cof"] = "([[:d:]]+)(.*)";
        rules["pow"] = "(.*)[^]([[:d:]]+)";
        rules["add"] = "\((.*)\)[+]\((.*)\)";
    }
    string derivative(string str)
    {
        s = generateSmatch(str);
        if(regex_match(str, rules["con"]))
            return "0";
        else if (regex_match(str, rules["xxx"]))
            return "1";
        else if (regex_match(str, rules["cof"]))
            return s[1].str() + "*" + derivative(s[2].str());
        else if (regex_match(str, rules["pow"]))
            return s[2].str() + s[1].str() + "^" + to_string(stoi(s[2].str()) - 1) + "*" + derivative(s[1].str());
        else if (regex_match(str, rules["add"])) {
             cout << "s[1]: " << s[1].str() << ", s[2]: " << s[2].str() << endl;
            return derivative(s[1].str()) + "+" + derivative(s[2].str());}
        return "";
    }
    smatch generateSmatch(string str)
    {
        smatch s;
        map<string, regex>::iterator it;
        for(it = rules.begin(); it != rules.end(); it++)
        {
            if(regex_match(str, s, it->second))
            {
                return s;
            }
        }
        return s;
    }
};
/*****************************************************************/
int main()
{
    ReadFile test("Equations.txt");
    string s = test.getFront();
    ExpressionAnalyzer e;
    cout << e.derivative(s) << endl;
}

我仍然不确定这里到底发生了什么。要了解更多信息,请使用调试器,逐步执行程序并在每个步骤后检查每个变量。或者添加更多的调试输出,以确保您知道您的程序在递归的哪个点失败。

然而,通过去掉循环(和整个generateSmatch() -函数),我能够让你的代码工作(几乎,见下文)。请注意,可能有一个更简洁的解决方案,因为在if语句中重复了很多代码,但是这个解决方案可以工作,我将把美化留给您。还要注意,这可能只是部分解决方案,因为我没有测试文件加载部分。因此,在调用此函数之前,请确保去掉额外的n和类似的内容。

#include <iostream>
#include <fstream>
#include <cmath>
#include <queue>
#include <stack>
#include <regex>
#include <vector>
#include <iterator>
#include <map>
#include <string>
using namespace std;
/*****************************************************************/

class ExpressionAnalyzer
{
    string expression;
    map<string, regex> rules;
public:
    ExpressionAnalyzer()
    {
        rules["con"] = "([[:d:]]+)";
        rules["xxx"] = "(x|\(x\))";
        rules["cof"] = "([[:d:]]+)(.*)";
        rules["pow"] = "(.*)[^]([[:d:]]+)";
        rules["add"] = "\((.*)\)[+]\((.*)\)";
    }
    string derivative(string str)
    {
        cout << "call with: " << str << endl;
        if(regex_match(str, rules["con"])){
            cout << "const!" << endl;
            return "0";
            }
        else if (regex_match(str, rules["xxx"])){
            cout << "xxx!" << endl;
            return "1";
        }
        else if (regex_match(str, rules["cof"])){
            cout << "cof!" << endl;
            smatch s;
            regex_match(str, s, rules["cof"]);
             cout << "s[1]: " << s[1].str() << ", s[2]: " << s[2].str() << endl;
            return s[1].str() + "*" + derivative(s[2].str());
            }
        else if (regex_match(str, rules["pow"])){
            cout << "pow!" << endl;
            smatch s;
            regex_match(str, s, rules["pow"]);
             cout << "s[1]: " << s[1].str() << ", s[2]: " << s[2].str() << endl;
            return s[2].str() + s[1].str() + "^" + to_string(stoi(s[2].str()) - 1) + "*" + derivative(s[1].str());
        }
        else if (regex_match(str, rules["add"])) {
            cout << "add!" << endl;
            smatch s;
            regex_match(str, s, rules["add"]);
             cout << "s[1]: " << s[1].str() << ", s[2]: " << s[2].str() << endl;
            return derivative(s[1].str()) + "+" + derivative(s[2].str());}
        else{
            cout << "not recognized!" << endl;
            return "";
        }
    }
};
/*****************************************************************/
int main()
{
    ExpressionAnalyzer e;
    cout << e.derivative("(x)") << endl;
    cout << e.derivative("(x^2)") << endl;
    cout << e.derivative("x^2") << endl;
    cout << e.derivative("(x^2)+(x)") << endl;
}
输出:

call with: (x)
xxx!
1                      <-result
call with: (x^2)
not recognized!
                       <-result (parantheses were not simplified away yet)
call with: x^2
pow!
s[1]: x, s[2]: 2
call with: x           <- recursion
xxx!
2x^1*1                 <-result (without parantheses: working)
call with: (x^2)+(x)
add!
s[1]: x^2, s[2]: x
call with: x           <- recursion
xxx!
call with: x^2         <- recursion
pow!
s[1]: x, s[2]: 2
call with: x           <- recursion lvl 2
xxx!
2x^1*1+1               <- result (YAY!)

我故意留下调试输出,也许它有助于看到,有时更详细的输出有助于看到内部发生了什么。

s是一个成员,在你的递归函数中你改变了它

s = generateSmatch(str);

将其转换为局部变量以获得预期结果:

string derivative(string str)
{
    smatch s;
    if(regex_match(str, s, rules["con"]))
        return "0";
    else if (regex_match(str, s, rules["xxx"]))
        return "1";
    else if (regex_match(str, s, rules["cof"]))
        return s[1].str() + "*" + derivative(s[2].str());
    else if (regex_match(str, s, rules["pow"]))
        return s[2].str() + s[1].str() + "^" + to_string(stoi(s[2].str()) - 1) + "*" + derivative(s[1].str());
    else if (regex_match(str, s, rules["add"])) {
         cout << "s[1]: " << s[1].str() << ", s[2]: " << s[2].str() << endl;
        return derivative(s[1].str()) + "+" + derivative(s[2].str());}
    return "";
}