相交文本以查找常用词

时间:2014-05-28 08:07:06

标签: javascript regex string text

我正在试图找出哪一种是最佳的交叉方式,一组文本并在其中找到常用词。鉴于这种情况:

var t1 = 'My name is Mary-Ann, and I come from Kansas!';
var t2 = 'John, meet Mary, she comes from far away';
var t3 = 'Hi Mary-Ann, come here, nice to meet you!';

交叉口结果应为:

var result =["Mary"];

它应该能够忽略.,!?-

之类的标点符号

正则表达式的解决方案是否最佳?

1 个答案:

答案 0 :(得分:12)

这是经过测试的解决方案:

function intersect() {
   var set = {};
   [].forEach.call(arguments, function(a,i){
     var tokens = a.match(/\w+/g);
     if (!i) {
       tokens.forEach(function(t){ set[t]=1 });
     } else {
       for (var k in set){
         if (tokens.indexOf(k)<0) delete set[k];
       }
     }
   });
   return Object.keys(set);
}

此函数是可变参数,您可以使用任意数量的文本调用它:

console.log(intersect(t1, t2, t3)) // -> ["Mary"] 

console.log(intersect(t1, t2)) // -> ["Mary", "from"] 

console.log(intersect()) // -> [] 

如果你需要支持非英语语言,那么这个正则表达式是不够的,因为Unicode在JavaScript正则表达式中支持不足。要么使用regex library,要么通过明确排除a.match(/[^\s\-.,!?]+/g);中的字符来定义正则表达式(这可能就足够了)。


详细说明:

这个想法是用第一个文本的标记填充一个集合,然后从集合中删除其他文本中缺少的标记。

  1. 该集合是用作地图的JavaScript对象。一些纯粹主义者会使用Object.create(null)来避免原型,我喜欢{}的简单性。
  2. 由于我希望我的函数为variadic,我使用arguments而不是将传递的文本定义为显式参数。
  3. arguments不是真正的数组,因此要迭代它,您需要for循环或类似[].forEach.call的技巧。它有效,因为arguments"array-like"
  4. 要进行标记化,我只需使用match来匹配单词,这里没有什么特别之处(请参阅上面关于更好地支持其他语言的说明)
  5. 我使用!i检查它是否是第一个文本。在这种情况下,我只需将标记复制为集合中的属性。必须使用值,我使用1。将来,ES6 sets会使意图更加明显。
  6. 对于以下文本,我迭代集合的元素(键),并删除那些不在标记数组中的元素(tokens.indexOf(k)<0
  7. 最后,我返回集合的元素,因为我们想要一个数组。最简单的解决方案是使用Object.keys