dollar
@dollar
Делай добро и бросай его в воду.

Чем заменить eval для простых выражений?

Например, нужно вычислить строку "x > 5 && (y == 7.5)"
Но нельзя использовать ни eval, ни new Function(), ни setTimeout(), ни onclick в элементах, потому что это как бы не безопасно.
Собственно, строка может быть произвольной. Суть в том, что там нет сложностей, только > < == != && || + - * / скобки и всякое такое.
Есть простые альтернативы eval?
  • Вопрос задан
  • 893 просмотра
Решения вопроса 3
lastuniverse
@lastuniverse
Всегда вокруг да около IT тем
Можно сделать так. Только на выходе будет строка.

var res = `${x > 5 && (y == 7.5)}`;

https://jsfiddle.net/jey5xs2r/1/

PS: могу предложить другое решение. Мной недавно была написана утилита для парсинга строк. Ее можно научить парсить как линейные структуры так и древовидные. Она возможно будет проигрывать в скорости узкоспециализированным решениям, но зато она универсальная, фактически швейцарский нож для парсинга структур любой сложности, что позволяет создать парсер и для HTML и для математических выражений и даже для кода при желании.

А это пример использования для вашей задачи:
код
const Splitter = require("split-tools");

var text = "x > 5 && (y == 7.5) || sin(Math.PI*a/360) || true";

const splitter = new Splitter({
    matchers: {
        function: /\s*([a-z]\w*)\(\s*(.*)\s*\)/g,
        bracket: /\(\s*(.*)\s*\)/g,
        operator: /\s*(\>|\<|\=\=|\!\=|\&\&|\|\||\+|\-|\*|\/|\%)\s*/g,
        variable: /\s*([a-z][\w\.]*)\s*/gi,
        sting: /\s*\"(.*?)\"\s*/gi,
        boolean: /\s*(true|false)\s*/gi,
        value: /\s*(\d[\d\.]*)\s*/gi
    }
});
 
 
const tree = {
    "brackets": ["function", "bracket", "operator", "variable", "sting", "boolean", "value"]
};
 
function subSplit(id, text) {
    console.log("subSplit:", id, "[", text, "]");
    if(tree[id] && tree[id].length)
        return splitter.process(text, tree[id]);
    return text;
}
 
 
splitter.addParser("function",(match,name,body)=>{
    return {
        type: "function",
        name: name,
        body: subSplit("brackets", body)
    };
});

splitter.addParser("bracket",(match,body)=>{
    return {
        type: "bracket",
        body: subSplit("brackets", body)
    };
});

splitter.addParser("operator",(match,body)=>{
    return {
        type: "operator",
        body: body
    };
});

splitter.addParser("variable",(match,body)=>{
    return {
        type: "variable",
        body: body
    };
});

splitter.addParser("string",(match,body)=>{
    return {
        type: "string",
        body: body
    };
});

splitter.addParser("boolean",(match,body)=>{
    return {
        type: "boolean",
        body: !!body
    };
});

splitter.addParser("value",(match,body)=>{
    return {
        type: "value",
        body: +body
    };
});
 
 
const list = splitter.process(text, tree.tags);
 
console.log("\n\nresult:\n",JSON.stringify(list, null, '  '));



На выходе из парсера будет массив пройдясь по которому можно будет вычислить значение распарсенного математического выражения:
результат
[
  { "type": "variable", "body": "x" },
  { "type": "operator", "body": ">" },
  { "type": "value", "body": 5 },
  { "type": "operator", "body": "&&" },
  { "type": "bracket", "body": [
      { "type": "variable", "body": "y" },
      { "type": "operator", "body": "==" },
      { "type": "value", "body": 7.5 }
    ]
  },
  { "type": "operator", "body": "||" },
  { "type": "function", "name": "sin",   "body": [
      { "type": "variable", "body": "Math.PI" },
      { "type": "operator", "body": "*" },
      { "type": "variable", "body": "a" },
      { "type": "operator", "body": "/" },
      { "type": "value", "body": 360 }
    ]
  },
  { "type": "operator", "body": "||" },
  { "type": "variable", "body": "true" }
]
Ответ написан
dollar
@dollar Автор вопроса
Делай добро и бросай его в воду.
Сделал решение на скорую руку - eval_lite.js.
Это тихий ужас, но работает.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы