Подтвердить что ты не робот

Безопасная оценка арифметических выражений в Javascript

Мне нужно оценить введенные пользователем арифметические выражения типа "2 * (3 + 4)" в Javascript, но я не хочу использовать eval по соображениям безопасности.

Я мог бы удалить все символы, которые не являются номерами или операторами, но я не уверен, что это было бы безопасно в любом случае, и было бы неплохо, если бы пользователь мог использовать такие функции, как cos, sqrt и т.д..

Существуют ли библиотеки JavaScript, которые выполняют оценку арифметических выражений?

4b9b3361

Ответ 1

вы можете попробовать JavaScript Expression Evaluator:

Эта библиотека является модифицированной версией Выражение ActionScript Raphael Grafs Parser. Когда я написал JavaScript Функция Плоттер, я хотел лучше альтернатива использованию JavaScripts eval Функция. Нет риска для безопасности в настоящее время, поскольку вы можете запускать кода в вашем собственном браузере, но его не как удобно для математики (Math.pow(2 ^ x) вместо 2 ^ x и т.д.).

тогда ваш код будет таким:

console.info ( Parser.evaluate( "2 * (3 + 4)" ) ); //prints 14

Ответ 2

Как уже упоминалось, наибольший урон, который может сделать любой пользователь, - это то, что они уже могут сделать, используя встроенную консоль в любом из основных браузеров. Однако, если вы хотите ограничить использование пользователем свойств Math/методов, вы можете написать простое регулярное выражение для обработки этого для вас. Что-то вроде этого должно работать:

function mathEval (exp) {
    var reg = /(?:[a-z$_][a-z0-9$_]*)|(?:[;={}\[\]"'!&<>^\\?:])/ig,
        valid = true;

    // Detect valid JS identifier names and replace them
    exp = exp.replace(reg, function ($0) {
        // If the name is a direct member of Math, allow
        if (Math.hasOwnProperty($0))
            return "Math."+$0;
        // Otherwise the expression is invalid
        else
            valid = false;
    });

    // Don't eval if our replace function flagged as invalid
    if (!valid)
        alert("Invalid arithmetic expression");
    else
        try { alert(eval(exp)); } catch (e) { alert("Invalid arithmetic expression"); };
}

Я понимаю, что вы не хотели использовать eval по соображениям безопасности, но регулярное выражение должно сделать его довольно безопасным, поскольку оно исключает любые слова, которые не являются прямыми свойствами объекта Math и большинства не-математических JS, включая оператор присваивания (=) и двоичные операторы. Более сложный метод заключается в написании токенизатора для синтаксического анализа математического выражения, поскольку он не является обычным языком.

Не стесняйтесь попробовать и разорвать рабочий рабочий пример Я написал, если вы можете или заметили проблему, оставьте комментарий, Посмотрим, что я могу сделать, чтобы исправить это.

<ч/" > Примечание. Йи Цзян упомянул в чат-чате JavaScript, что также может быть полезно разрешить строчные буквы для таких вещей, как Math.PI. В этом случае вы можете просто добавить следующий оператор else if в функцию замены:

else if (Math.hasOwnProperty($0.toUpperCase())
    return "Math."+$0.toUpperCase();

Добавьте его между операторами if и else (пример).

Ответ 3

Вы можете использовать расширенный синтаксический анализатор выражения из math.js, который не использует JavaScript eval.

http://mathjs.org

Использование:

var ans = math.eval('2 * (3 + 4)');

или использовать парсер (который поддерживает назначение переменных и функций):

var parser = math.parser();
var ans = parser.eval('2 * (3 + 4)');

Ответ 4

Вы можете использовать регулярное выражение для замены всего, кроме вашего белого списка. Но поскольку javascript выполняется на клиенте (если вы не используете HTTP-сервер AOL), любой, кто может изменять входные данные, может также изменить код, поэтому вы не делаете его любым больше или менее безопасно, чем это уже есть.

Ответ 5

Попробуйте nerdamer

var result = nerdamer('sqrt(4)+cos(1)-2').evaluate();
document.getElementById('text').innerHTML = result.text();
<script src="http://nerdamer.com/js/nerdamer.core.js"></script>
<div id="text"></div>