【问题标题】:Javascript dynamic IF regex condition without eval?没有eval的Javascript动态IF正则表达式条件?
【发布时间】:2014-07-05 17:22:41
【问题描述】:

我正在向网络应用程序添加多组复选框过滤(多个无序列表的复选框),但我一直在尝试使用 eval 来解决问题(或者在这种情况下我不应该担心?)。基本上,数据是通过一个 AJAX 调用来调用的,我将其存储在一个对象数组中,并且我正在进行实时过滤而不进行额外的 AJAX 调用。当复选框被选中时,我正在使用 .match() 并且我基本上将正则表达式创建为数组中的字符串值(k 是类别对象属性,例如 category1):

filterArgs.push("(data['" + k + "'].join(', ').match(/" + filters[k].join('') + ".+/))");

filters 数组在上面的循环中设置,看起来像这样(v 是实际的字符串值 - 类别名称):

filters[k][z] = '(?=.*\\b' + v[z] + '\\b)';

那我加入 filterArgs:

return filterArgs.join(' && ');

filterArgs 当前通过 eval 传递给 if 语句条件,如下所示:

if(eval(filter_setup())){

因此,如果该 if 语句为真,则主数据数组中的正确对象将包含在过滤后的数据集中。我可能会切换到 jQuery 的 $.grep 而不是那个 if 语句,但我仍然遇到同样的 eval 问题。还有其他方法可以构建动态正则表达式吗?它与 eval 一起工作得很好,但我已经阅读了所有文章说它是多么“邪恶”。 if 语句条件最终如下所示(在第一组中选中了 2 个框,在另一组中选中了 1 个框):

(data['type'].join(', ').match(/(?=.*\bRestaurant\b)(?=.*\bBar\b).+/)) && (data['state'].join(', ').match(/(?=.*\bWashington\b).+/))

【问题讨论】:

  • 这听起来绝对像是一个 XY 问题。您可以使用内置的 RegExp 构造函数构建动态正则表达式。
  • ^^ 我的想法完全正确,将字符串直接传递给RegExp
  • 别忘了在用户输入中转义()[]{}\*+^$.?
  • 是的,您正在构建的 filterArgs 不是要走的路;只需在循环中一次运行一个 ifs;如果有任何返回 false,则整体返回 false。不需要评估。 eval 永远是不可原谅的,顺便说一句,除非你真的真的知道你在做什么并且你正在解决大约 3 个问题之一(即使在这些情况下,通常最好改为编写自己的解释器)

标签: javascript jquery regex filtering eval


【解决方案1】:

你可以推送一个函数,而不是推送一个表达式:

 filterArgs.push(function(k){
   var re = new RegExp(filters[k].join('') + ".+");
   return function(data){
     return data[k].join(', ').match(re);
   }
 });

现在您可以执行函数而不是评估字符串:

 for(var cond = true, i = 0; cond && i < filterArgs.length; i++) {
   cond &= filterArgs[i](data);
 }

【讨论】:

    【解决方案2】:

    尽可能避免eval。在这种情况下,绝对没有必要。

    在需要时存储filter 对象并定义如下内容:

    function checkFilters(data, filters) {
        for (var k in filters) {
            if (!(new RegExp(filters[k].join("")).test(data[k])))
                return false;
        return true;
    }
    

    所以你可以这样使用它:

    if (checkFilters(data, filters)) {
        ...
    }
    

    顺便说一句,使用构造函数创建RegExp 对象的成本很高。如果您需要更快的速度,您可以预编译过滤器并保留它们而不是条件数组:

    filters[k] = new RegExp(filters[k].join(""));
    

    此外,正如 Dave 所说,根据您的数据,您可能需要转义过滤器:

    filters[k][z] = '(?=.*\\b'
            + v[z].replace(/([\^\$\/\.\*\+\?\|\(\)\[\]\{\}\\])/g, "\\$1")
            + '\\b)';
    

    【讨论】:

    • 谢谢。转义过滤器是我的下一步,所以很高兴你也包含它。
    • 我对此进行了更多测试,但它实际上并没有像我希望的那样工作。使用这种方法,过滤似乎只基于过滤器组之一进行过滤。如果选择了来自不同组的过滤器,则仅根据第一个过滤器组进行过滤。
    • 好的,我想我在之前的评论中提到的问题已经解决了。我没有从 for 循环返回,而是将循环上方的布尔变量设置为 true,如果 RegExp 失败则将其设置为 false,然后在循环后返回布尔变量(如果为 true)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多