Парсер мат. операции в уравнении

Столкнулся с банальной проблемой парсера математического уравнения. Собсно, есть код на c#, задача которого решение математического уравнения, и для этого он парсит каждую математическую операцию, по типу a+b с наличием переменной х и возможными степенями, целого или дробного числа, отрицательного и положительного числа.

Вот пример парсера операции вычисления:

reg = new Regex(@"(([-+]?)(((\d+)((\,(\d+))?)((x((\^(\d+))?))?))|(x((\^(\d+))?))((\/(((\d+)((\,(\d+))?)((x((\^(\d+))?))?))|(x((\^(\d+))?))))?))(((-)([-+]?)(((\d+)((\,(\d+))?)((x((\^(\d+))?))?))|(x((\^(\d+))?)))((\/(((\d+)((\,(\d+))?)((x((\^(\d+))?))?))|(x((\^(\d+))?))))?))))");

Со своей задачей справляется, если на входе будет уравнение с искомой операцией не идущей подряд, то есть a-b или a-b+c-d. В таком случае, он спарсит a-b в первом случае или a-b и c-d во втором. Но когда встречается a-b-c, спарсится только первое соответствие. То есть, я понимаю, что регулярные выражения продолжают искать соответствия начиная с того места, после предыдущего найденого соответствия. НО все же, можно ли как то заставить поиск искать все возможные соответствия. Или гибкие регулярные выражения не настолько гибкие?

PS хотелось бы, конечно, по возможности допилить именно этот шаблон, иначе придется переделывать функции, что очень лень. Но если иначе никак, то что уж поделать...


Ответы (2 шт):

Автор решения: Laukhin Andrey

Я согласен со всеми комментариями относительно подходов к решению, и возможно этот ответ не уместен. Но если мы говорим о частном случае разбора простых уравнений, без скобок, то мне просто больно смотреть на вашу регулярку.

Я бы использовал одно выражение для проверки корректности ввода уравнения, а второе для выделения членов уравнения.

Код на JS для демонстрации работы РВ:

check.onclick = () => {
  clearGrid();

  let value = equation.value.replaceAll(' ', '');
  let check = /^(?:[-+*\/]?\b(?:\d+x?|x))+=(?:[-+*\/]?\b(?:\d+x?|x))+$/.test(value);

  if (check) {
    let matches = value.matchAll(/(=)()()|([-+*\/]?)(?:(\d+)(x?)|()(x))/mg);
    for (const m of matches) {
      let data = m.filter(v => v !== undefined);
      data.every(v => grid.innerHTML += `<span class="m">${v}</span>`);
    };
  } else {
    console.log('Уравнение задано с ошибками!');
  }
}

function clearGrid() {
  let cells = [...document.querySelectorAll('.m')];
  cells.every(v => v.remove() || true);
}
#grid {
  display: grid;
  grid-template-rows: 1fr 1fr 1fr 1fr;
  grid-auto-flow: column;
  margin-top: 1em;
  width: min-content;
}

#grid span {
  border-bottom: 1px solid gray;
  padding: 0.1em 0.5em;
  white-space: nowrap;
}
<input id="equation" type="text" value="3x + 5 - 9 = 10x + 7 - x" />
<button id="check">Проверить</button>
<div id="grid">
  <span>member</span>
  <span>sign</span>
  <span>value</span>
  <span>variable</span>
</div>

Как получить эти группы на С#:

string pattern  = @"(=)()()|([-+*\/]?)(?:(\d+)(x?)|()(x))";
string input    = @"3x+5-9=-10x+7-x";

string[] names  = { "member", "sign", "value", "variable" };

foreach (Match m in Regex.Matches(input, pattern))
{
    int index = 0;

    for (int i = 0; i < m.Groups.Count; i++)
    {
        if(m.Groups[i].Success)
            Console.WriteLine(names[index++ % 4] + ": " + m.Groups[i].Value);
    }

    Console.WriteLine("");
}
→ Ссылка
Автор решения: Олег Устинов

Как вариант можно разбить на массив

String myString = "a+b-c*d/e";
String[] result=myString.split("[-+*/]");

И дальше уже работать с массивом, и также забрать массив оператором

Возможно костыль, но и задача довольно не тривиальная

→ Ссылка