Всем мой пламенный шалом. Я пытаюсь парсить математические выражения, которые перевожу в вид для исполнения на php. И вот встречается такое, например, "50-10%" Для парсинга такой код PHP: $text = preg_replace('/(\d+)[+-](\d+)\%/', \1*\2/100)', $text); Вполне вроде рабочий. Но вот беда, что может встретится такое выражение, например "(1+(1+3)*10)-10%" Как такое запарсить, если учесть что вложенных скобок может быть сколько угодно?
Выражения не парсятся регулярками. Читайте про обратную польскую нотацию, к примеру. В сети можно найти алгоритмы и перевода выражения к обратной польской нотации, и вычисления выражения, записанного в обратной польской нотации. --- Добавлено --- Есть и другие подходы - к примеру, прямая польская нотация, но насколько с ВУЗа помню, в обратной польке считать проще.
Я читал про нее конечно когда думал как все это парсить, но я, честно говоря, так и не понял, как она поможет мне решать уравнения с переменной. Хотел поискать примеры, но они либо на C++ и мне почти не понятны, либо слишком банальные на простой арифметике (2+2)*3
https://pear.php.net/package/Math_RPN/docs/latest/math/_Math_RPN-1.1.2---Math---RPN.php.html https://github.com/rin-nas/php-math-rpn
Ну так какая задача: разобрать выражение или решить произвольное уравнение с одной переменной? --- Добавлено --- Для всего существуют свои методы. К примеру, системы линейных уравнений решаются методом моего однофамильца Крамера. Алгоритм решения произвольных уравнений наверняка существует, поскольку такие программы есть, но мне не известен (может, я до него не дожил в ВУЗе, который не закончил)
Ну я парсю для чего? чтобы решить! Я их разбираю и перевожу в вид для исполнения php. пользователь вводит типа 8*20%-(34+6)+3^2 - перевожу в 8*0,2-(34+6)+pow(3,2) и ему ответ. Уже наговнокодил с регулярками и работает, правда с некоторыми оговорками Дальше хочу расширить для решений типа 2+5x=10+x или 2^x=8
Это две совершенно разные задачи. Первая полностью решается с помощью обратной польки. Идея перевести в синтаксис php и прогнать через eval мне не сильно нравится (потому что я не люблю eval), хотя может быть и можно. Универсальный решатель уравнений - это несколько совсем иное. Если только линейные уравнения и только квадратные - это одно. Если произвольные - там сложный алгоритм, поскольку тут уже вступает. Ну первое уравнение решается на раз два, второе тоже, но если тебе вводят произвольное уравнение, тут уже надо придумывать что-то супер-универсальное, без кучи условий типа "если это линейное уравнение, то так, если квадратное - то так, если степенное - то вот эдак. Тебе же вполне могут ввести 2^x + x^2 + sin(x/2) = 14. Это я от балды, поэтому решения не знаю, но это уравнение тоже может теоретически иметь корни. --- Добавлено --- Тут нужно подтягивать соответствующий математический аппарат, типа http://yandex.ru/clck/jsredir?from=...0n=ru&cts=1491583587842&mc=4.1867043459100275
Сложное не потяну, на данный момент задача покрыть банальные примеры из курса средней школы: арифметика и простые уравнения с одной переменной. Сейчас бы просто арифметику отладить. Собственно говоря вместо польской записи, 3 строчки года с регуляркой и эвал. Мне кажется у меня проще. Единственное не могу решать, как применять степень и вычитание процентов к скобкам - ну собственно сама тема этому посвящена. Остальное все работает С eval все в норме - перед этим все разбирается, так что лишний код туда не пойдет точно.
Ну если говорить про eval, то со степенью проблем не должно быть - начиная с php 5.6 у нас есть оператор **, а пользоваться сейчас чем-то меньшим для новых проектов - глупость. Так что можно просто заменять уголок на двойную звёздочку банальным str_replace. С процентами да, сложнее. Думать надо. Можно попробовать preg_replace_callback
Вот за такое спасибо. А то я сам чет тупил, когда читал документацию, даже не обратил внимание на ** А с процентами что-то тоже тупил - решил -+ процент менять на умножение. "-50%" на "*0,5" на "+50" на "*1,5" Вроде норм, хотя может еще что всплывет... И все таки получается регулярками парсить математические выражения проще, чем делать обратную польскую запись PHP: $text = '(55-50)^2+√(9)' //входная строка $patterns = array ('/\^/' ,'/√\((\d+[.]{0,1}[\d]{0,})\)/'); // расширяем на все условия $replace = array ('**','sqrt(\1)'); // расширяем на все условия $text = preg_replace($patterns, $replace, $text); eval(); Вместо кучи кода перегона из стеки в стеки операторов и операндов...