Неверное разделение регулярных выражений из-за схожих критериев поиска с другим соответствием - PullRequest
0 голосов
/ 13 февраля 2019

У меня есть калькулятор CLI, и я добавляю функцию квадратного корня.У меня есть это регулярное выражение, которое анализирует входные данные пользователей:

string.scan(/\d*\.?\d+\^?|[-+\/*%()]|sqrt\(\d*\.?\d+\)/)

Он работает с этими входами, как и ожидалось:

calc -o "sqrt(9)" #=> ["sqrt(9)"]
calc -o "sqrt(9) + sqrt(9)" #=> ["sqrt(9)", "+", "sqrt(9)"]

Однако, мое регулярное выражение не учитывает вложенный sqrt.При этом,

calc -0 "sqrt(6+3)"

Я хочу вывод:

["sqrt(6+3)"]

, потому что когда программа находит sqrt во время поиска, она просто рекурсивно применяет метод scan с регулярным выражениемпока он не войдет в самую глубокую вложенную формулу и вернется обратно.Но я получаю:

["(", "6", "+", "3", ")"]

Я пытался захватить все, кроме квадратных скобок, но он также захватывает все в других скобках.Так что у меня возникают проблемы с захватом sqrt(9) и sqrt(6+3) без единой путаницы с другим.

Любое руководство очень ценится.

ОБНОВЛЕНИЕ: Поэтому, следуя предоставленному ответу, возможно, яМне нужно больше объяснить мою программу, чтобы вы поняли, что происходит.

Скажем, у меня есть ввод 2 * (3 + 5), это будет интерпретировано в следующем массиве:

["2", "*", "(", "3", "+", "5", ")"]

Таким образом, программа соответствует PEDMAS, поэтому сначала будет искать круглые скобки, в этой ситуации она их найдет.Основной цикл в основном выглядит следующим образом:

function find_backets
   start_i, end_i
   for i in array do 
      if i == "("
         start_i = index
         find_brackets
      end
      if i == ")"
         end_i = index
         # end of nest
      end
   end

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

calc -o "2 * (6 + (2 * 2))"

#=> ["2", "*", "(", "6", "+", "(", "2", "*", "2", ")", ")"]

Моя идея состоит в том, что, когда он сталкивается с функцией sqrt, он просто просто повторно используетто же самое регулярное выражение, которое используется для ввода данных пользователем, и создайте новый массив и сделайте с ним вышеописанное.Затем, как только это будет сделано, я беру индекс 0 и помещаю его туда, где раньше был sqrt.

РЕДАКТИРОВАТЬ: Так что да, на самом деле не упоминалось, я собираюсь захватить полностью sqrt.Итак, все и вся в чем-то вроде sqrt(5+5*(6/2+sqrt(9))

ОБНОВЛЕНИЕ: Я думаю, что нашел решение

Так что я немного почитал, чтобы узнать, как * + ?, и это сработало немного больше иЯ думаю (по крайней мере, пока), что это работает

string.scan(/\d*\.?\d+\^?|[-+\/*%()^]|sqrt\(.+?\)+|pi/)

calc -o "sqrt(9)" #=> ["sqrt(9)"] 
calc -o "sqrt(3+6)" #=> ["sqrt(3+6)"]
calc -o "sqrt(9) + sqrt(9)" #=> ["sqrt(9)", "+", "sqrt(9)"]
calc -o "sqrt(9) + 2" #=> ["sqrt(9)", "+", "2"]

Обновится немного

1 Ответ

0 голосов
/ 13 февраля 2019

Есть несколько проблем, которые мешают вам: во-первых, регулярное выражение не обрабатывает рекурсивный поиск, поэтому вы не сможете найти соответствующие скобки.Если вы хотите иметь возможность принимать выражения в скобках внутри sqrt(), вам нужно атаковать его под другим углом (ответ там указывает на этот алгоритм ).

Если вы ожидаете совпадения только с простыми выражениями внутри sqrt(), то следующая проблема: в вашем подвыражении sqrt вы необязательно сопоставляете буквенный символ периода \.? между цифрами, но вы не позволяете никаких операторов.Вы можете подойти к этому напрямую, добавив совпадение для операторов и необязательный второй float в это подвыражение.В следующем примере я обернул дополнение в группу без захвата (?:_expression_) и использовал *, чтобы сопоставить его 0 или более раз.

sqrt\(\d*\.?\d+\) становится sqrt\(\d*\.?\d+(?: *?[-+\/*%]? *?\d*\.?\d*)*\)

Наконец, вы, скорее всего, захотите оценить содержимое из sqrt() перед оценкой самого sqrt().Для этого вам нужно использовать группы захвата.Есть несколько способов, с помощью которых вы могли бы подойти к этому, но один из них - заключить все выражение в неэкранированные скобки (группа захвата 1), тогда содержимое sqrt() также должно быть заключено в неэкранированные скобки (группа захвата 2).

/(\d*\.?\d+\^?|[-+\/*%()]|sqrt\((\d*\.?\d+(?: *?[-+\/*%]? *?\d*\.?\d*)*)\))/

Результатами вашего сканирования будет массив массивов групп захвата.Запуск его с "sqrt(9) + sqrt(9)" вернет [["sqrt(9)", "9"], ["+", nil], ["sqrt(9)", "9"]], поэтому в любое время группа захвата 2 не nil, она содержит содержимое sqrt().

Вы можете увидеть это регулярное выражение в действии на Regexr

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...