使用QRegExp的二次方程解析器

时间:2013-09-11 18:44:09

标签: c++ regex qt equation-solving

我想使用正则表达式为二次方程实现解析器。我想将它作为控制台应用程序保留。我完成了正则表达式并在Debuggex中进行了测试。目前我有2个问题 - 我无法从(ax ^ 2 + bx + c)获得a,b,c,我想用向上和向下箭头添加类似bash的历史记录。提前致谢。我的代码:

#include <QCoreApplication>
#include <QRegExp>
#include <QString>
#include <QTextStream>
#include <QStringList>
#include <QDebug>
#include <cstdio>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    Q_UNUSED(a);

    QTextStream cin(stdin, QIODevice::ReadOnly | QIODevice::Text);
    QTextStream cout(stdout, QIODevice::WriteOnly | QIODevice::Text);

    const QString regexText = R"(^[-]?\d*x\^2\s*[+,-]\s*\d*x\s*[+,-]\s*\d*$)";

    while(true)
    {
        QRegExp regex(regexText);

        cout << "Enter an equation to solve or press EOF(Ctrl+D/Z) to exit." << endl;
        cout << "--> " << flush;

        QString equation;
        equation = cin.readLine();

        if( equation.isNull() )
        {
            cout << endl;
            cout << "Thanks for using quadric equation solver! Exitting..." << endl;
            return 0;
        }

        int pos = regex.indexIn(equation);
        QStringList captures = regex.capturedTexts();
        qDebug() << captures;
    }
}

1 个答案:

答案 0 :(得分:2)

我认为你正在研究如何正确使用捕获组,而debuggex并不能很好地向你展示结果。我会更多地沿着这些方向拍摄正则表达式:

^(-?\d*)x\^2\s*([+-]\s*\d*)x\s*([+-]\s*\d+)?$

您可以在RegExr,我首选的RegEx工具中查看它。将鼠标悬停在突出显示的匹配项上,以查看组已捕获的内容。

您可以看到括号基本上是对可以单独提取的子表达式进行删除,并对其进行解析。我已经选择包含操作(+/-),因此您可以使用它来解析系数的正面或负面性质。您将在示例数据中看到它不包括小数系数,但您的原始表达式也没有,我认为这是最紧迫的问题。

小数

捕获小数就像在捕获的每组数字后添加剪切一样简单:

(?:\.\d+)?

其中可选地匹配(不捕获)文字句点,后跟其他一些数字。这会将您更大的正则表达式转换为:

^(-?\d*(?:\.\d+)?)x\^2\s*([+-]\s*\d*(?:\.\d+)?)x\s*([+-]\s*\d+(?:\.\d+)?)?$

其中as you can see允许捕获十进制表达式。它们仍然必须有序(正则表达式的缺点,但只有当你尝试一次完成所有事情时),但是你增加了可以解决的问题数量。

重新排序

下一步是处理乱序表达式。您可以在一个正则表达式中执行此操作,但我建议不要使用它,原因如下:

  1. 阅读并因此维护
  2. 非常糟糕
  3. 在单个RegEx中执行此操作会使排除多余信息变得困难。
  4. 分段解决自动解决多个术语的问题(如x^2+x+x+2
  5. 分段操作可以让您更轻松地捕获更高阶的多项式。
  6. 1:验证

    第一个基本步骤是确定术语的含义。对我来说,术语是运算符,后跟可选的空格,后跟变量表达式或常量。 OR:

    [+-]\s*(?:\d+(?:\.\d+)?|\d*(?:\.\d+)?x(?:\^\d+(?:\.\d+)?)?)
    

    这是一个很糟糕的,所以我将包括Debuggex可视化。

    Regular expression visualization

    围绕表达方式的方式缠绕你的头,因为它是下一个表达的基本单位:

    ^-?\s*(?:\d+(?:\.\d+)?|\d*(?:\.\d+)?x(?:\^\d+(?:\.\d+)?)?)(?:\s*[+-]\s*(?:\d+(?:\.\d+)?|\d*(?:\.\d+)?x(?:\^\d+(?:\.\d+)?)?))+$
    

    当你在Debuggex中看到那个时,很明显它基本上只是前一个表达式重复了一次或多次。我添加了一些空格,并给第一个空格而不是操作符,但它基本上是相同的。

    Regular expression visualization

    现在,这里缺少一些空间,添加负数或减去正数。 (想想,3x + -4x ^ 2),但这是对正则表达式的一个小改动,所以我想我会继续前进。将正则表达式与您的线匹配(当然,修剪),并且您可以知道您有一个有效的等式。

    2。提取

    提取基于单个正则表达式,经过修改以捕获特定术语。它确实需要能够使用前瞻,我必须承认一些正则表达式引擎不支持。但Debuggex支持它,我没有找到确认或拒绝QRegExp,所以我将包括它。

    ((?:^-?|[+-])\s*d*(?:\.\d+)?)
    

    这是您的基本正则表达式。单独使用,它将捕获一个数字,而不考虑它是一个系数还是常数。要捕获常量,请添加否定前瞻以确保其后面没有变量:

    ((?:^-?|[+-])\s*d*(?:\.\d+)?)(?!\s*x)
    

    要捕获特定的指数,只需匹配它,然后是空格或其他符号。:

    ((?:^-?|[+-])\s*d*(?:\.\d+)?)\S*x\^2(?=[\s+-])
    

    要在没有指数的情况下进行捕获,请使用否定前瞻以确保它缺失:

    ((?:^-?|[+-])\s*d*(?:\.\d+)?)\s*x(?!\^)
    

    虽然,就个人而言,我更愿意一次性捕获所有变量术语:

    ((?:^-?|[+-])\s*d*(?:\.\d+)?)\s*x(?:^(\d+(?:\.\d+)?))
    

    其中只有两个捕获组:一个用于系数,一个用于指数。

相关问题