将包含布尔值的字符串转换为布尔类型

3
如果我有这个;
  var a = "(true && false) && true && false"

如果我想评估这个字符串,有哪些选项?

如果我说,这段代码将在浏览器中生成,但绝对不会有用户输入,那么使用eval是否安全?

如果不安全,解析它的最高效方法是什么?

编辑:

顺便说一下,该字符串是动态的,所以我不能保证它总是像上面那样,它可能是:

  var a = "(true && false) || (true && (true && false)) && true && false"

提醒: 我知道可以使用eval,但我想知道为什么不应该使用eval,或者是否有其他选择?

编辑:原始问题:

 var a = function(){ return false} // all of them always return a boolean
 var b = function(){ return true}
 var c = function(){ return true}
 var d = function(){ return false}

 var conditions = "(a && b) && c && d"

我无法更改上述代码,我需要解析它,我需要对条件进行评估;

3
我很好奇。有这样一个字符串的用例是什么? - str
1
@RajshekarReddy:你为什么要那样做?那样做没有任何帮助。 - Cerbrus
1
你需要使用 eval(),如果你想坚持这种方式,我认为没有其他方法。 - Mr. Alien
1
@str,这段代码是由第三方生成的,用于非常复杂的规则系统,其中规则用数字(1 && 2)定义,每个数字指向一个返回布尔值的函数,最终你会得到一串布尔值的字符串。 - Milad
@Milad:你能“获取”这些数字吗?那个第三方返回什么?你有访问你提到的那些函数的权限吗? - Cerbrus
显示剩余8条评论
3个回答

2

function ExecuteJavascriptString() {
    var n = 0;
    var s = "(true || false) || (true || (true || false)) && true";
    var ifstate = " if (" + s + ") { console.log('done'); } ";
    setTimeout(ifstate, 1);
}

ExecuteJavascriptString()


将存储为字符串的JavaScript代码执行 - user7633250
2
这可能和eval一样邪恶。 - Arg0n
1
但是等一下,这不和 eval 一样吗?我仍然可以在这个字符串中放入恶意代码并运行它,对吧? - Milad

0

我在想,在运行eval之前,你可以至少验证字符串是否包含你认为应该包含的内容,使用正则表达式/(?:(?:true)|(?:false)|(?:&&)|(?:\|\|)|[()\s])/g

var validExp = "(true && false && true) || (true && (true && false)) && true";
var evilExp = "(true && false && true) || (true && (true && false)) && true function() { console.log('do evil stuff'); }";

console.log(evalBoolStr(validExp)); //false
console.log(evalBoolStr(evilExp)); //Invalid input

function evalBoolStr(str) {
  if(str.match(/(?:(?:true)|(?:false)|(?:&&)|(?:\|\|)|[()\s])/g).join('') === str) {
    return eval(str);
  }
  return 'Invalid input';
}


0

尝试实际编写布尔字符串解析器:

function parseBoolStr(str) {
  var expressions = {};
  var expressionRegex = new RegExp("\\((?:(?:!*true)|(?:!*false)|(?:&&)|(?:\\|\\|)|\\s|(?:!*\\w+))+\\)");
  var expressionIndex = 0;
  str = str.trim();
  while (str.match(expressionRegex)) {
    var match = str.match(expressionRegex)[0];
    var expression = 'boolExpr' + expressionIndex;
    str = str.replace(match, expression);
    match = match.replace('(', '').replace(')', '');
    expressions[expression] = match;
    expressionIndex++;
  }
  return evalBoolStr(str, expressions);
}

function evalBoolStr(str, expressions) {
  var conditions = str.split(' ');
  if (conditions.length > 0) {
    var validity = toBoolean(conditions[0], expressions);
    for (var i = 1; i + 1 < conditions.length; i += 2) {
      var comparer = conditions[i];
      var value = toBoolean(conditions[i + 1], expressions);
      switch (comparer) {
        case '&&':
          validity = validity && value;
          break;
        case '||':
          validity = validity || value;
          break;
      }
    }
    return validity;
  }
  return 'Invalid input';
}

function toBoolean(str, expressions) {
  var inversed = 0;
  while (str.indexOf('!') === 0) {
    str = str.replace('!', '');
    inversed++;
  }
  var validity;
  if (str.indexOf('boolExpr') === 0) {
    validity = evalBoolStr(expressions[str], expressions);
  } else if (str == 'true' || str == 'false') {
    validity = str == 'true';
  } else {
    validity = window[str]();
  }
  for (var i = 0; i < inversed; i++) {
    validity = !validity;
  }
  return validity;
}

var exp1 = "(true && true || false) && (true || (false && true))";
var exp2 = "(true && false) && true && false";
var exp3 = "(true && !false) && true && !false";
var exp4 = "(a && b) && c && d";

console.log(exp1 + ' = ' + parseBoolStr(exp1));
console.log(exp2 + ' = ' + parseBoolStr(exp2));
console.log(exp3 + ' = ' + parseBoolStr(exp3));
console.log(exp4 + ' = ' + parseBoolStr(exp4));

function parseBoolStr(str) {
  var expressions = {};
  var expressionRegex = new RegExp("\\((?:(?:!*true)|(?:!*false)|(?:&&)|(?:\\|\\|)|\\s|(?:!*\\w+))+\\)");
  var expressionIndex = 0;
  str = str.trim();
  while (str.match(expressionRegex)) {
    var match = str.match(expressionRegex)[0];
    var expression = 'boolExpr' + expressionIndex;
    str = str.replace(match, expression);
    match = match.replace('(', '').replace(')', '');
    expressions[expression] = match;
    expressionIndex++;
  }
  return evalBoolStr(str, expressions);
}

function evalBoolStr(str, expressions) {
  var conditions = str.split(' ');
  if (conditions.length > 0) {
    var validity = toBoolean(conditions[0], expressions);
    for (var i = 1; i + 1 < conditions.length; i += 2) {
      var comparer = conditions[i];
      var value = toBoolean(conditions[i + 1], expressions);
      switch (comparer) {
        case '&&':
          validity = validity && value;
          break;
        case '||':
          validity = validity || value;
          break;
      }
    }
    return validity;
  }
  return 'Invalid input';
}

function toBoolean(str, expressions) {
  var inversed = 0;
  while (str.indexOf('!') === 0) {
    str = str.replace('!', '');
    inversed++;
  }
  var validity;
  if (str.indexOf('boolExpr') === 0) {
    validity = evalBoolStr(expressions[str], expressions);
  } else if (str == 'true' || str == 'false') {
    validity = str == 'true';
  } else {
    validity = window[str]();
  }
  for (var i = 0; i < inversed; i++) {
    validity = !validity;
  }
  return validity;
}

function a() {
  return false;
}
function b() {
  return true;
}
function c() {
  return true;
}
function d() {
  return false;
}

使用方法就是 parseBoolStr('true && false'); //false


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接