Как вычислить математическое уравнение (BODMAS) в php?

#php #math #eval

#php #математика #вычисление

Вопрос:

Для этого мне просто нужна базовая простая функция.

Вот моя попытка:

 function parseEq($eq) {
    $char = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']; 
    $achar = array_map('ord', $char);

    $eq = str_replace($char, $achar, $eq);

    return eval(strtr('return {eq};', [
        '{eq}' => strtr($eq, [
            '=' => '==',
        ])
    ]));
}
  

но это работает только для некоторых примеров:

 var_dump(parseEq('2x = 2x'));
var_dump(parseEq('a   b = b   a'));
var_dump(parseEq('x - x = 0'));
var_dump(parseEq('y/2 = (1/2)*y'));
var_dump(parseEq('-(-x) = x'));
  

но не для этих 2

 var_dump(parseEq('2(x   y) = 2x   2y'));
var_dump(parseEq('2x = 2*x'));
  

Ответ №1:

 <?php
function parseEq($eq) {
        $char = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
        $achar = array_map('ord', $char);

        // debug
        echo $eq . PHP_EOL;

        $eq = str_replace($char, $achar, $eq);

        // debug
        echo $eq . PHP_EOL;

        return eval(strtr('return {eq};', [
                '{eq}' => strtr($eq, [
                        '=' => '==',
                ])
        ]));
}
  

выдаст

 2x = 2x
2120 = 2120
bool(true)
a   b = b   a
97   98 = 98   97
bool(true)
x - x = 0
120 - 120 = 0
bool(true)
y/2 = (1/2)*y
121/2 = (1/2)*121
bool(true)
-(-x) = x
-(-120) = 120
bool(true)
2(x   y) = 2x   2y
2(120   121) = 2120   2121
PHP Parse error:  syntax error, unexpected '(' in parseEq.php(16) : eval()'d code on line 1
bool(false)
2x = 2*x
2120 = 2*120
bool(false)
  

итак, он пытается заменить каждую букву на ее обычное значение, например, x на 120.

С небольшими изменениями

 <?php
function parseEq($eq) {
    $char = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
    $achar = array_map('ord', $char);

    echo $eq . PHP_EOL;

    // replaceing 2( or 2x with 2* or 2*x
    $eq = preg_replace('/(d )([(a-z])/', "$1*$2", $eq);
    echo $eq . PHP_EOL;

    $eq = str_replace($char, $achar, $eq);

    echo $eq . PHP_EOL;

    return eval(strtr('return {eq};', [
        '{eq}' => strtr($eq, [
            '=' => '==',
        ])
    ]));
}
  

это привело бы к

     2x = 2x
    2*x = 2*x
    2*120 = 2*120
    bool(true)
    a   b = b   a
    a   b = b   a
    97   98 = 98   97
    bool(true)
    x - x = 0
    x - x = 0
    120 - 120 = 0
    bool(true)
    y/2 = (1/2)*y
    y/2 = (1/2)*y
    121/2 = (1/2)*121
    bool(true)
    -(-x) = x
    -(-x) = x
    -(-120) = 120
    bool(true)
    2(x   y) = 2x   2y
    2*(x   y) = 2*x   2*y
    2*(120   121) = 2*120   2*121
    bool(true)
    2x = 2*x
    2*x = 2*x
    2*120 = 2*120
    bool(true)
  

итак, теперь это работает

Комментарии:

1. это здорово … как насчет выполнения полномочий? Нравится '(x^2)*(x^3) = x^5'

2. php.net/manual/en/function.pow.php , это должно сработать, если вы замените ^ на ** (начиная с PHP 5.6). Более низкая версия вы можете использовать preg_replace для изменения x ^ 5 в pow (x, 5)