我想使用正则表达式为二次方程式实现解析器。我想将其保留为控制台应用程序。我完成了正则表达式并在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/