确认文档出现次数

3
我在创建一个程序时遇到了极大的困难,该程序基于我设定的规则检查文档的出现次数。借助正则表达式,我检查某些字段,如果特定字段存在,则可以计算其出现次数或进行更深入的扫描。这有点令人困惑,而我不知道该如何确切地解释。
我正在检查文本文件,但为了减少复杂性,我将使用数组。
我有以下数组:
let strings = [
  'COMPANY: NAME  ID: 12',
  'COMPANY: NAME  ID: 12',
  'COMPANY: NAME  ID: 12',
  'COMPANY: NAME2 ID: 10'
];

以下是期望的输出结果:

{
  'NAME' :  { '12': 3 },
  'NAME2':  { '10': 1 }
}

为了实现这一目标,我需要进行一些检查,因此我想出了以下的“MAP”:
let patterns = [
  {
    'pattern': 'COMPANY:\\s*?([\\w]+)\\s',
    'modifier': ''
  },
  {
    'pattern'  : 'ID:\\s*?(\\d{2})\\s*',
    'modifier' : ''
  }
];

我很难创建伪代码,我知道这是可以通过递归完成的,但我卡住了。最大的问题是因为嵌套,我可能会有几个层级的嵌套,不一定是两个。
在过去的几个小时里,我创建了以下代码:

'use strict';

let patterns = [
  {
    'pattern': 'COMPANY:\\s*?([\\w]+)\\s',
    'modifier': ''
  },
  {
    'pattern'  : 'ID:\\s*?(\\d{2})\\s*',
    'modifier' : ''
  }
];

let strings = [
  'COMPANY: NAME  ID: 12',
  'COMPANY: NAME  ID: 12',
  'COMPANY: NAME  ID: 12',
  'COMPANY: NAME2 ID: 10'
];

var _data = {};
for (let string of strings) {

  var root = _data;

  for (let i = 0, length = patterns.length; i < length; i++) {

    let item   = patterns[i];

    let regex  = new RegExp(item.pattern, item.modifier);
    let result = regex.exec(string);

    if (i < patterns.length -1) {
      root = root[result[1]] = {};
    } else {
      root = root[result[1]] = 1;
    }
  }
}

document.body.innerHTML = JSON.stringify({_data});

我正在尝试获取最后一部分,即统计出现的次数,这让我很头疼。也许递归或生成器可以解决这个问题。

更新 -

重要的是要理解,应该适用于3,4,5个对象。例如:

let patterns = [
  {
    'pattern': 'COMPANY:\\s*?([\\w]+)\\s',
    'modifier': ''
  },
  {
    'pattern'  : 'ID:\\s*?(\\d{2})\\s*',
    'modifier' : ''
  },
  {
    'pattern'  : 'SOMETHING:\\s*?(\\d+)\\s*',
    'modifier' : ''
  }
];

let strings = [
  'COMPANY: NAME  ID: 12 SOMETHING: 1010',
  'COMPANY: NAME  ID: 12 SOMETHING: 1010',
  'COMPANY: NAME  ID: 12 SOMETHING: 1010',
  'COMPANY: NAME2 ID: 10 SOMETHING: 1010'
];

输出应该是:
{
  'NAME': {
    '12': {
      '1010': 3
    }
  },
  'NAME2': {
    '10': {
      '1010': 1
    }
  }
}
3个回答

0
你可以这样做。对于这些任务,Array.prototype.reduce()非常方便。

var strings = [
  'COMPANY: NAME  ID: 12',
  'COMPANY: NAME  ID: 12',
  'COMPANY: NAME  ID: 12',
  'COMPANY: NAME2 ID: 10'
],

reduced = strings.reduce((p,c) => {var co = c.match(/\w+(?=\s*ID)/)[0],
                                   id = c.match(/\d+$/)[0];
                                   p[co] ? p[co][id]++ : p[co] = {[id]:1};
                                   return p},{});
document.write("<pre>" +JSON.stringify(reduced,null,2) + "</pre>");

现在我修改了代码,使其能够处理无限嵌套属性。我不得不使用两个我的发明对象方法Object.prototype.getNestedValue()Object.prototype.setNestedValue(),它们用于通过动态提供的参数访问、设置/修改嵌套对象属性及其值。提供的最后一个参数是要获取或设置的值。之前的参数是嵌套属性。它们对于这些用例非常方便。所以就这样。

Object.prototype.getNestedValue = function(...a) {
  return a.length > 1 ? (this[a[0]] !== void 0 && this[a[0]].getNestedValue(...a.slice(1))) : this[a[0]];
};
Object.prototype.setNestedValue = function(...a) {
  a.length > 2 ? typeof this[a[0]] === "object" && this[a[0]] !== null ? this[a[0]].setNestedValue(...a.slice(1))
                                                                       : (this[a[0]] = typeof a[1] === "string" ? {} : new Array(a[1]),
                                                                                 this[a[0]].setNestedValue(...a.slice(1)))
                      : this[a[0]] = a[1];
  return this;
};


var strings = [
  'COMPANY: NAME  ID: 12 SOMETHING: 1010 MORE: 857',
  'COMPANY: NAME  ID: 12 SOMETHING: 1010 MORE: 857',
  'COMPANY: NAME  ID: 12 SOMETHING: 1010 MORE: 857',
  'COMPANY: NAME2 ID: 10 SOMETHING: 1010 MORE: 333'
],

reduced = strings.reduce((p,c) => {var props = c.match(/(?::\s*)[^\s]+/g).map(e => e.split(":")[1].trim()),
                                       value = p.getNestedValue(...props);
                                   !!value ? p.setNestedValue(...props,++value) : p.setNestedValue(...props,1);
                                   return p},{});

document.write("<pre>" + JSON.stringify(reduced,null,2) + "</pre>");


非常困难对吧?我已经尝试了至少2天。 - user6332096
@D_REIS,由于你说它可以无限嵌套对象,所以这个问题有点“复杂”,但我正在处理。我会想出一个答案。 - Redu
1
@D_REIS 是的,那正是我现在正在处理的。 - Redu
@D_REIS,希望这对您没问题。 - Redu
1
@vp_arth:获取嵌套结构中要使用的属性并不是 OP 的主要问题。问题在于,一旦您拥有这些属性,动态构建嵌套结构就成了难点,而不管这些属性的数量如何。OP 可以轻松使用任何正则表达式将源文本拆分为所需的属性集,然后此代码将完成其余工作。 - Redu
显示剩余4条评论

0
'use strict';

    let patterns = [
      {
        'pattern': 'COMPANY:\\s*?([\\w]+)\\s',
        'modifier': ''
      },
      {
        'pattern'  : 'ID:\\s*?(\\d{2})\\s*',
        'modifier' : ''
      },
      {
        'pattern'  : 'EFD:\\s*?(\\d{2})\\s*',
        'modifier' : ''
      }
    ];

let strings = [
  'COMPANY: NAME  ID: 12 SOMETHING: 1010',
  'COMPANY: NAME  ID: 12 SOMETHING: 1010',
  'COMPANY: NAME  ID: 12 SOMETHING: 1010',
  'COMPANY: NAME2 ID: 10 SOMETHING: 1010'
];

    var result = {};
    strings.forEach(function(value, index) {
        var split = value.replace(/ +(?= )/g,'').split(" ");
      var name = split[1];
      var correspondingValue = split[3];
      var efd = split[5];


      if (!(result[name])) {
        result[name] = {};
        result[name][correspondingValue] = {};
        result[name][correspondingValue][efd] = 1;
      } else {
        result[name][correspondingValue][efd]++;
      }

    });

    document.body.innerHTML = JSON.stringify(result);

谢谢Samir。这个解决方案只适用于两个对象,如果我有三个对象怎么办?http://codepen.io/anon/pen/MyMjEV?editors=0010 - user6332096
嗨,我修改了答案以包括第三个对象。 - samir benzenine

0

这不是ES6的解决方案,但相对简单易懂:

var strings = [
  'COMPANY: NAME  ID: 12 SOMETHING: 1010',
  'COMPANY: NAME  ID: 12 SOMETHING: 1010',
  'COMPANY: NAME  ID: 12 SOMETHING: 1010',
  'COMPANY: NAME2 ID: 10 SOMETHING: 1010',
  'COMPANY: NAME2 ID: 11 SOMETHING: 1010'
];

var output = {};

for (var i = 0; i < strings.length; i++) {
    var line = strings[i];
    // regex to extract only the values from the current line
    // e.g (NAME, 12, 1010)
    var matches = line.match(/[^\s:]+(?=\s+[^:]+:|$)/g);
    var currentObj = output;
    for (var y = 0; y < matches.length; y++) {
        var match = matches[y];
        var value = currentObj[match];

        // if the value is not the deepest field, 
        //   then create the deeper object to hold the next iteration's values
        // else if it is the deepest field then store the appropriate count
        currentObj[match] = y < matches.length - 1
                              ? value || {}
                              : value ? value + 1 : 1;

        // set up for the next iteration
        currentObj = currentObj[match];
    }
}

console.log(output);

输出:

{
   'NAME':{
      '12':{
         '1010':3
      }
   },
   'NAME2':{
      '10':{
         '1010':1
      },
      '11':{
         '1010':1
      }
   }
}

这里有演示
正则表达式演示


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