我想使用正则表达式为二次方程实现解析器。我想将它作为控制台应用程序保留。我完成了正则表达式并在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;
}
}
答案 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允许捕获十进制表达式。它们仍然必须有序(正则表达式的缺点,但只有当你尝试一次完成所有事情时),但是你增加了可以解决的问题数量。
下一步是处理乱序表达式。您可以在一个正则表达式中执行此操作,但我建议不要使用它,原因如下:
x^2+x+x+2
)第一个基本步骤是确定术语的含义。对我来说,术语是运算符,后跟可选的空格,后跟变量表达式或常量。 OR:
[+-]\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),但这是对正则表达式的一个小改动,所以我想我会继续前进。将正则表达式与您的线匹配(当然,修剪),并且您可以知道您有一个有效的等式。
提取基于单个正则表达式,经过修改以捕获特定术语。它确实需要能够使用前瞻,我必须承认一些正则表达式引擎不支持。但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+)?))
其中只有两个捕获组:一个用于系数,一个用于指数。