Найдите ответ на строковое уравнение без использования eval ()

Мне нужен способ взять уравнение, заданное в виде строки, и найти математический ответ, главное предостережение в том, что я не могу использовать eval ().

Я знаю, что уравнение всегда будет содержать только числа, четыре математических оператора (т.е. * / + -) и круглые скобки, оно может иметь или не иметь пробелов в строке. Вот пара примеров.

4 * 4
4+6/3
(3 / 2)*(4+8)
(4+8) * 2

Я предполагаю, что это нужно будет сделать с каким-то регулярным выражением?


person RMcLeod    schedule 26.11.2009    source источник
comment
Оценивать строковые формулы довольно просто, когда они такие простые. См. Полдюжины ответов на странице stackoverflow .com / questions / 1384811 /   -  person Ira Baxter    schedule 26.11.2009


Ответы (2)


Математические выражения не являются регулярными. Они контекстно-свободные.

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

person Welbog    schedule 26.11.2009
comment
Удивительно, как много можно узнать, просто прочитав ответы на вопросы! Для меня это в новинку, круто! +1 - person Ben Fransen; 26.11.2009
comment
Это даст вам фору: $tokens = token_get_all('<?php ' . $expression) - person Steve Clay; 26.11.2009

На всякий случай, если кого-то интересует алгоритм, который я придумал в PHP для создания обратной польской нотации.

function convertToRPN($equation)

{
    $equation = str_replace(' ', '', $equation);
    $tokens = token_get_all('<?php ' . $equation);
    $operators = array('*' => 1, '/' => 1, '+' => 2, '-' => 2);
    $rpn = '';
    $stack = array();
    $size = count($tokens);                                                 
    for($i = 1; $i < $size; $i++) {
        if(is_array($tokens[$i])) {
            $rpn .= $tokens[$i][1] . ' ';
        } else {
            if(empty($stack) || $tokens[$i] == '(') {
                $stack[] = $tokens[$i];
            } else {
                if($tokens[$i] == ')') {
                    while(end($stack) != '(') {
                        $rpn .= array_pop($stack);
                    }
                    array_pop($stack);
                } else {
                    while(!empty($stack) && end($stack) != '(' && $operators[$tokens[$i]] >= $operators[end($stack)]) {
                        $rpn .= array_pop($stack);
                    }
                    $stack[] = $tokens[$i];
                }
            }
        }
    }

    while(!empty($stack)) {
        $rpn .= array_pop($stack);
    }

    return $rpn;
}
person RMcLeod    schedule 27.11.2009