Я хочу реализовать синтаксический анализатор для квадратного уравнения, используя регулярные выражения. Я хочу сохранить его как консольное приложение. Я сделал регулярное выражение и проверил его в Debuggex. В настоящее время у меня есть 2 проблемы — я не могу получить a, b, c от (ax ^ 2 + bx + 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;
}
}
Я думаю, что вы хотите узнать, как правильно использовать захват групп, отладка которых не очень хороша, чтобы показать вам результат. Я бы стрелял для регулярного выражения более по этим направлениям:
^(-?\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+)?)?$
Который, как вы видете, позволяет захват десятичных выражений. Они все еще должны быть в порядке (недостаток регулярных выражений, но только когда вы пытаетесь сделать все сразу), но вы увеличили количество проблем, которые вы можете решить.
Следующим шагом является работа с неупорядоченными выражениями. Вы можете сделать это в одном регулярном выражении, но я рекомендую против этого по нескольким причинам:
x^2+x+x+2
)Первый базовый шаг — решить, как выглядит термин. Для меня термин — оператор, сопровождаемый дополнительным пробелом, сопровождаемый выражением переменной или константой. ИЛИ ЖЕ:
[+-]\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+)?))
Который имеет ровно две группы захвата: одна для коэффициента и одна для показателя степени.
Других решений пока нет …