如何使用JavaScript评估集合包含测试?

时间:2018-08-18 11:57:30

标签: javascript arrays set

我想评估表达式以检查真实性。

用户以

的形式给我表达
x == y || a == (c + 3)

y >= 4

我只将eval用于:

expression.replace(/[^|()\d\+-><=!&]/g, '');
eval(expression);

现在用户想给我设置包含表达式,如:

5 ∈ y || 3 ∉ y

y是一个数组。处理该问题的最佳安全方法是什么?

编辑:感谢您的帮助,仔细阅读答案很难决定选择哪个/更好。

2 个答案:

答案 0 :(得分:2)

只需检查自己是否包含Repo.insert! %Language{ page: "accounts", code: "en-us", mode: "all", language: { "username_email" : "Username or email address", "password" : "Password", "invalid_username_password" : "Invalid username or password" } }, prefix: :lookups ,就可以用add_filter('wp_insert_post_data', 'delete_invalid_posts', 99); function delete_invalid_posts($data) { $false_titles = array("*****", "******"); $title_arr = explode(' ', $data['post_title']); $found = array_intersect($false_titles, $title_arr); if (!empty($found)) { $data['post_status'] = 'trash'; } return $data; } eval替换包含测试。为了实现您可以按名称访问集合,可以将它们分组为对象true,其中键是名称,值是集合本身(请参见下面的示例):

纳入测试:

false

排除测试:

sets

示例:

var newString = string.replace(/(\S+)\s*∈\s*(\S+)/g, function(match, item, set) {
    var theActualSet = ...;                  // get the actual set using 'set'
    return theActualSet.includes(+item);
});

现在可以轻松进行评估而无需担心,只需除去var newString = string.replace(/(\S+)\s*∉\s*(\S+)/g, function(match, item, set) { var theActualSet = ...; // get the actual set using 'set' return !theActualSet.includes(+item); }); 和文字var sets = { y: [1, 2, 3, 4, 5] }; var string = "5 ∈ y || 3 ∉ y"; var newString = string.replace(/(\S+)\s*∈\s*(\S+)/g, function(match, item, set) { var theActualSet = sets[set]; return theActualSet && theActualSet.includes(+item); }); newString = newString.replace(/(\S+)\s*∉\s*(\S+)/g, function(match, item, set) { var theActualSet = sets[set]; return theActualSet && !theActualSet.includes(+item); }); console.log("The original string: '" + string + "'"); console.log("The result string: '" + newString + "'"); console.log("The result: " + eval(newString));|()\d\+-><=!&以外的任何内容,然后使用true即可得出评估。

注意:您可以使用falseeval来代替10,以便更轻松地删除不需要的字符:{ {1}}

答案 1 :(得分:1)

实际上很难用a E b替换b.includes(a),因为您必须注意操作员的先行性。因此,唯一的方法似乎是实现自己的解析器:

 const diad = (char, operation) => input =>  {
   // If the operator doesnt exist, don't evaluate
   if(!input.includes(char))
     return input;
   return input.split(char)
     .map(evaluate) // deep first
     .reduce(operation); // left to right
 };

 const bracketsFirst = input => {
   const opening = input.lastIndexOf("("); // the most inner one
   const closing = input.indexOf(")", opening);

   if(opening === -1 || closing === -1) // no brackets, don't evaluate here
     return input;

   const before = input.slice(0, opening);
   const after = input.slice(closing + 1);
   const middle = input.slice(opening + 1, closing);

   return before + evaluate(middle) + after; // just evaluate the thing in the brackets 
};

 let context = {};
 const evaluate = input => [
   bracketsFirst,
   // Boolean algebra
   diad("||", (a, b) => a || b), // lowest operator predescendence
   diad("&&", (a, b) => a && b),
   // Comparison:
   diad("==", (a, b) => a === b),
   diad("!=", (a, b) => a != b),
   diad("<=", (a, b) => a <= b),
   diad(">=", (a, b) => a >= b),
   diad("<", (a, b) => a < b),
   diad(">", (a, b) => a > b),
   // Math:
   diad("+", (a, b) => a + b),
   diad("-", (a, b) => a - b),
   diad("*", (a, b) => a * b),
   diad("/", (a, b) => a / b),
   // The custom operator:
   diad("E", (a, b) => b.includes(a)),
   // Booleans
   a => a.trim() === "true" ? true : a,
   a => a.trim() === "false" ? false : a,
   // Number literals & Identifiers
   a => +a || context[a.trim()] || a,
   a => { throw Error("Unknown:" + a) }
 ].reduce((out, fn) => typeof out === "string" ? fn(out) : out, input);

因此您可以这样做:

 context.a = [1,2,3];
 context.one = 1;
 evaluate("1 E a || 5 E a"); // false
 evaluate("one == 1(5 - 5) - 9"); // true :)

Try it!