2010-10-25 5 views
8

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

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 см: Can php eval return a boolean value?

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

+0

Если вам нужно сделать более сложные вещи, WolframAlpha offers an API для разработчиков. – TheMagician

+0

@ TheMagician Хорошая идея, но, к сожалению, их нужно уволить очень часто (тысячи из них в секунду), поэтому внешний api не будет работать. –

ответ

4

Eval не является злом !!!!!

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

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

+1

preg_replace, чтобы выражение «safe» становилось более неудобным, если выражение может содержать такие функции, как log(), sin() ... OP не указывает, действительно ли это так. –

+0

Согласен - его более неловко - но далеки от невозможности реализовать. Важно использовать белый список, а не черный список. – symcbean

+0

Спасибо за Eval не злой ответ :) –

0

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

-1

Eval()

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

PHPClasses

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

+2

-1 для предложения использования eval() для ввода пользователем – Hammerite

+2

-1 nice !!! Это очень опасно для пользователей, как было указано в качестве требования в этом вопросе. –

+0

@ Hammerite, @Mark Baker: эй, я пишу, что никогда не приятно использовать eval ... – Cesar

0

Зависит ...

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

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

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

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

12

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

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

Посмотрите на класс evalMath на PHPClasses. Он должен делать все, что вы указали здесь.

EDIT

Re: К сожалению evalMath не обрабатывает вещи, как (х> 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 теперь будет обрабатывать (х> 5), (х < 5) или (х = 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)')); 

Далее Edit

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

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

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

+1

@ae - не так много работы, чтобы получить evalMath для обработки (x> 5) и т. Д. Казалось бы, вы бы скорее использовали eval(), несмотря на опасности, но посмотрите мое редактирование изменений участвует. –

+0

Thats great! Я дам ему время и посмотрю, как это происходит. –

1

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

1 - x/2 

становится

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

Это немного сложнее, чтобы написать парсер, но это очень легко оценить обработанную формулу.

1

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

-1

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

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

Смежные вопросы