Безопасная оценка арифметических выражений в Javascript
Мне нужно оценить введенные пользователем арифметические выражения типа "2 * (3 + 4)" в Javascript, но я не хочу использовать eval
по соображениям безопасности.
Я мог бы удалить все символы, которые не являются номерами или операторами, но я не уверен, что это было бы безопасно в любом случае, и было бы неплохо, если бы пользователь мог использовать такие функции, как cos
, sqrt
и т.д..
Существуют ли библиотеки JavaScript, которые выполняют оценку арифметических выражений?
Ответы
Ответ 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>