如何为对象实现glob **?

时间:2017-01-10 00:23:53

标签: javascript search recursion glob

如何通过JavaScript对象支持globstar风格的**搜索?

这就像lodash的_.get一样,只是要查询的对象可以包含这些特殊的***属性,如果没有完全匹配则会匹配这些属性

在下面的示例代码中,{ **: { middleName: 3 }}规则应与以下路径匹配:

['middleName']
['clients', 'middleName']
['clients', '0', 'middleName']

由于**匹配0个或更多元素,因此{**: { middleName: x }}基本上匹配任何以'middleName'结尾的数组并返回x

但是,由于一个*规则,它只匹配一个级别(恰好是1个具有任何值的元素),因此应该优先于{{ 1}},导致第二条路径评估为**

在实践中,我不太关心优先权,因为我不应该写重叠"规则",但我无法弄清楚如何实施{{ 1}}无论如何。

如果你需要一个更实际的例子,我打算用它来做的是:1,2,3号码将被验证器功能和"路径"取代。将是{ lastName: 2 }个名字。通过这种方式,我可以为表单指定验证规则。

另外,我真的只想返回叶子节点,所以其中一个返回**的事实有点奇怪,但它是一个边缘情况我不太关心。如果<input>优先于此,因为它是叶子节点匹配,我想这会更好。

代码:

&#13;
&#13;
{ lastName: 2 }
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:2)

问题似乎很像文件路径通配。代码中的规则对象似乎有点奇怪。不确定你是如何结束它或它的更广泛的目的可能但是......我认为你可以将你的规则从一个对象重构为glob路径。有很多JS包用于globbing。以下是使用minimatch globber的重构(在原始列表中添加规则以显示如何使用glob表达式减少冗余)。

var minimatch = require("minimatch")
var _ = require('underscore')

rules = {
  'firstName': 1,
  'clients/*/lastName': 2,
  '**/middleName': 3,
  'people/*/+(middleName|lastName)': 4,
}
rule_keys = _.keys(rules).sort().reverse() // Force a well defined match order.

function glob(rules, path) {
  path = path.join('/')
  for(r of rule_keys) {
    if(minimatch(path, r)) {
      return rules[r];
    }
  }
}

paths = [
  [['firstName'], "1"],
  [['clients', '0', 'lastName'], "2"],
  [['clients', '0', 'middleName'], "should be 3"],
  [['clients', 'middleName'], "should be 2|3"],
  [['middleName'], "should be 3"],
  [['people', '0', 'middleName'], "should be 4"],
];

for(p in paths) {
  console.log(glob(rules, paths[p][0]), paths[p][1]);
}

实际上,minimatch实现可能会将字符串表达式解释为类似于您所显示的对象 - 除了更复杂,因为它支持更多功能。