c++ - 使用QRegExp的二次方程式解析器

标签 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;
    }
}

最佳答案

我认为您正在寻找学习如何正确使用捕获组的方法,而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允许捕获十进制表达式。它们仍然必须是有序的(正则表达式的缺点,但仅当您尝试同时执行所有操作时才是如此),但是您增加了可以解决的问题的数量。

重新排序

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


很难阅读,因此无法维护
在单个RegEx中执行此操作将很难排除无关的信息。
分段执行可自动解决多个术语的问题(例如x^2+x+x+2
分段进行设置可以使您更轻松地捕获高阶多项式。


1:验证

第一步是确定一个术语的外观。对我来说,术语是运算符,后跟可选的空格,后跟变量表达式或常量。要么:

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


这有点麻烦,所以我将包括Debuggex可视化。



绕开表达式的工作方式,因为它是下一个表达式的基本单元:

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


当您在Debuggex中看到一个表达式时,很明显它基本上只是前一个表达式重复了一次或多次。我添加了一些空格,并为第一个空格提供了一个可选的负数,而不是运算符,但是本质上是相同的。



现在,这里缺少一些空间,可以添加负数或减去正数。 (想想,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+)?))


恰好有两个捕获组:一个用于系数,另一个用于指数。

关于c++ - 使用QRegExp的二次方程式解析器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18748919/

相关文章:

javascript - 仅从 Express 静态目录提供 .js 文件?

c# - 正则表达式模式问题

qt - QNetwork TLS 可移植

c++ - 使用基于模板参数的一组函数重载构建可变参数模板类?

c++ - 无法推导成员函数包装器的返回类型

c++ - LNK1169 和 LNK2005 错误

regex - sed linux 命令无法插入行

c++ - 使用 Qt 的正则表达式捕获一些文本

qt - 将参数传递给 QStackedWidget 中小部件的构造函数

c++ - 映射按键事件qt