Обработка математических уравнений в php

Пользователю разрешено вводить любое математическое уравнение, которое им нравится (с одной переменной):

x + 5

1 - x/2

(x/3) * (56/13)

Они хранятся в виде строк в базе данных. Когда они извлекаются, мне нужно подставить «x» для числа и проверить значение уравнения.

Как я могу это сделать?

Я подумывал написать парсер для деконструкции строк и превратить их в уравнения, однако это звучит дорого и проблематично. Другой вариант – передать их через eval (но я не большой поклонник использования eval, если могу помочь).

Есть идеи?

UPDATE: Мне также нужно получить логическое значение чего-то типа «(x> 5)». Это невозможно с evalMath

ОБНОВЛЕНИЕ 2: Мне нужно запустить много из них в секунду. Я изучаю eval в php, но не могу заставить его возвращать логическое значение для (5> 4), но я заметил, что js сделает это … возможно, мне следует исследовать node.js …

ОБНОВЛЕНИЕ 3: После того, как вы повеселились, попробовав node.js (и заставив его работать), я вернулся и получил eval для работы на PHP: см. Php eval возвращает логическое значение?

Поэтому я поеду с eval с очень хардкорным фильтром на пользовательский ввод.

Eval не злой !!!!!

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

Это просто оставляет возможность нападений с инъекцией кода, чего легко избежать, делая preg_replace на каждом из них, который не является безопасным символом (то есть 0 …. 9, (,), +, -, *, /, ^, .)

Мой стандартный ответ на этот вопрос всякий раз, когда он возникает:

Не используйте eval (особенно, поскольку вы заявляете, что это пользовательский ввод) или изобретайте колесо, написав собственный анализатор формул.

Взгляните на класс evalMath на PHPClasses. Он должен делать все, что вы указали здесь.

РЕДАКТИРОВАТЬ

re: К сожалению, evalMath не обрабатывает такие вещи, как (x> 5)

изменить линии 177-179

 $ops = array('+', '-', '*', '/', '^', '_', '>', '<', '='); $ops_r = array('+'=>0,'-'=>0,'*'=>0,'/'=>0,'^'=>0, '>' => 0, '<' => 0, '=' => 0); // right-associative operator? $ops_p = array('+'=>0,'-'=>0,'*'=>1,'/'=>1,'_'=>1,'^'=>2, '>' => 0, '<' => 0, '=' => 0); // operator precedence 

изменить строку 184 на

 if (preg_match("/[^\w\s+*^\/()\.,-<>=]/", $expr, $matches)) { // make sure the characters are all good 

Добавить

 case '>': $stack->push($op1 > $op2); break; case '<': $stack->push($op1 < $op2); break; case '=': $stack->push($op1 == $op2); break; 

после строки 321

и evalMath теперь будет обрабатывать (x> 5), (x <5) или (x = 5)

 // instantiate a new EvalMath $m = new EvalMath; $m->suppress_errors = true; // set the value of x $m->evaluate('x = 3'); var_dump($m->evaluate('y = (x > 5)')); 

Дальше Править

Пропущенная строка 307, которая должна быть изменена следующим образом:

 if (in_array($token, array('+', '-', '*', '/', '^', '>', '<', '='))) { 

Если вы имеете дело с пользовательским вводом, я бы держался подальше от eval. Напишите анализатор и разделите формулу на вложенные массивы.

 1 - x/2 

становится

 Array ( [0] => - [1] => 1 [2] => Array ( [0] => / [1] => x [2] => 2 ) ) 

Немного сложно написать парсер, но очень легко оценить анализируемую формулу.

немного рискованная возможность, если вы используете код в ящике Linux, – это использовать команду bc (убедитесь, что вы правильно выбрали свои входы, прежде чем передать ее системе cmd). я не могу сказать, что использование системы намного лучше, чем риски eval, поэтому я ожидаю здесь некоторых downvotes.

Даже если вы пройдете через eval, вам придется заменить x на некоторое число. Какой бы стратегией я ни занимался, это передать значение для x и посмотреть, что такое оцененное значение. Если это больше, чем 0, я бы попробовал меньшее число, и если он меньше 0, я бы попробовал большее число рекурсивно, пока он не удовлетворит порог ошибки (<> 0,001%).

Зависит…

Какую сложность он примет? Потому что для общих математических уравнений (как и те, которые вы опубликовали), я не вижу слишком большой проблемы при написании парсера. Главным проблемным вопросом будет круглый номер и место правильной скобки.

Но если уравнения собираются принимать «продвинутые» входы, такие как {[()]}, или X², X³, или получить дальнейшее, дифференциальное исчисление и математику колледжа, так что все может сойти с ума.

Если сложность достигает символической обработки, попробуйте прочитать и найти что-нибудь о CAS (Calculate Algebra Systems).

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

Eval ()

Зависит от того, что вам нужно делать, но в любом случае, самый дешевый способ сделать это, используя функцию замены для переменных, а затем запустить выражение с помощью eval ().
Конечно, вам нужно сначала убедиться, что ваши формулы находятся в синтаксисе php.
Хорошо, что вы можете использовать любую математическую функцию, поддерживаемую php, что плохо, никогда не приятно использовать eval () 🙂

PHPClasses

Другим хорошим вариантом является просмотр веб-страниц до тех пор, пока вы не найдете парсер: P
http://www.phpclasses.org/package/2695-PHP-Safely-evaluate-mathematical-expressions.html

Использование eval- функции очень опасно, если вы не можете управлять строковым аргументом.

Попробуйте Matex для расчета математических математических формул. Он поддерживает также переменные и пользовательские функции.