在文本中查找关键字

时间:2013-01-09 23:35:03

标签: javascript regex if-statement find match

我有一个已发生事件的数组,这些事件是用自由文本编写的,因此除了某些关键字之外没有遵循模式,例如。 “抢劫”,“凶手”,“入室盗窃”,“车祸”等。这些关键字可以在文本中的任何位置,我想找到这些关键字并将其添加到类别中,例如。 “抢劫”。

最后,当我检查了所有事件时,我想要一个这样的类别列表:

Robberies: 14
Murder attempts: 2
Car accidents: 5
...

数组元素如下所示:

incidents[0] = "There was a robbery on Amest Ave last night...";
incidents[1] = "There has been a report of a murder attempt...";
incidents[2] = "Last night there was a housebreaking in...";
...

我想这里最好的是使用正则表达式来查找文本中的关键字,但我真的很喜欢regexp,因此需要一些帮助。

下面的正则表达式不正确,但我猜这个结构会起作用吗? 有没有更好的方法来避免DRY?

var trafficAccidents = 0,
    robberies = 0,
    ...

function FindIncident(incident) {
    if (incident.match(/car accident/g)) {
        trafficAccidents += 1;
    }
    else if (incident.match(/robbery/g)) {
        robberies += 1;
    }
    ...
}

提前多多感谢!

7 个答案:

答案 0 :(得分:2)

实际上,我在这里不同意你的观点。 。 。我认为像indexOf这样的字符串函数可以完美地运行。

我会使用JavaScript的indexOf方法,该方法需要2个输入:

  

string.indexOf(值,startPos);

因此,您可以做的一件事是将一个简单的临时变量定义为光标。 。

function FindIncident(phrase, word) {
    var cursor = 0;
    var wordCount = 0;
    while(phrase.indexOf(word,cursor) > -1){
        cursor = incident.indexOf(word,cursor);
        ++wordCount;        
    }
    return wordCount;
}

我没有测试过代码,但希望你能得到这个想法。 。

如果您使用它,请特别注意起始位置。

答案 1 :(得分:2)

以下代码显示了您可以采取的方法。您可以对其进行测试here

var INCIDENT_MATCHES = {
  trafficAccidents: /(traffic|car) accident(?:s){0,1}/ig,
  robberies: /robbery|robberies/ig,
  murder: /murder(?:s){0,1}/ig
};

function FindIncidents(incidentReports) {
  var incidentCounts = {};
  var incidentTypes = Object.keys(INCIDENT_MATCHES);
  incidentReports.forEach(function(incident) {
    incidentTypes.forEach(function(type) {
      if(typeof incidentCounts[type] === 'undefined') {
        incidentCounts[type] = 0;
      }
      var matchFound = incident.match(INCIDENT_MATCHES[type]);
      if(matchFound){
          incidentCounts[type] += matchFound.length;
      };
    });
  });

  return incidentCounts;
}

正则表达式是有意义的,因为即使您只考虑复数和单数形式的“抢劫”中的差异,您也会有许多符合“匹配”标准的字符串。您还希望确保匹配不区分大小写。

您需要在正则表达式上使用“全局”修饰符,以便匹配“谋杀,谋杀,谋杀”等字符串,并将计数增加3而不是仅增加1。

这允许您将匹配条件和事件计数器之间的关系保持在一起。它还避免了对全局计数器的需求(授权INCIDENT_MATCHES在这里是一个全局变量,但是您可以轻松地将其放在其他地方并将其从全局范围中删除。

答案 2 :(得分:1)

使用对象存储数据。

events = [
    { exp : /\brobbery|robberies\b/i, 
    //       \b                      word boundary
    //         robbery               singular
    //                |              or
    //                 robberies     plural
    //                          \b   word boundary
    //                            /i case insensitive
      name : "robbery",
      count: 0
    },
    // other objects here
]

var i = events.length;    
while( i-- ) {

    var j = incidents.length; 
    while( j-- ) {

        // only checks a particular event exists in incident rather than no. of occurrences
        if( events[i].exp.test( incidents[j] ) { 
            events[i].count++;
        }
    }
}

答案 3 :(得分:1)

RegEx也让我头疼。 ;)如果您正在寻找完全匹配并且不担心拼写错误和拼写错误,我会在事件字符串中搜索包含您正在寻找的关键字的子字符串。

incident = incident.toLowerCase();
if incident.search("car accident") > 0 {
    trafficAccidents += 1;
}
else if incident.search("robbery") > 0 {
    robberies += 1;
}
...

答案 4 :(得分:1)

使用一个对象数组来存储您正在搜索的所有不同类别,包括一个合适的正则表达式和一个count成员,您可以用四行写出整个内容。

var categories = [
    {
        regexp: /\brobbery\b/i
        , display: "Robberies"
        , count: 0
    }
    , {
        regexp: /\bcar accidents?\b/i
        , display: "Car Accidents"
        , count: 0
    }
    , {
        regexp: /\bmurder\b/i
        , display: "Murders"
        , count: 0
    }
];

var incidents = [ 
    "There was a robbery on Amest Ave last night..."
    , "There has been a report of an murder attempt..."
    , "Last night there was a housebreaking in..."
];

for(var x = 0; x<incidents.length; x++)
    for(var y = 0; y<categories.length; y++)
        if (incidents[x].match(categories[y].regexp))
            categories[y].count++;

现在,无论您需要什么,您只需编辑一段代码,它就会传播到您的代码中。

此代码有可能对多个类别中的每个事件进行分类。为了防止这种情况,只需在if块中添加一个'break'语句。

答案 5 :(得分:1)

你可以做类似这样的事情,它将获取数组中每个项目上找到的所有单词,它将返回一个带有计数的对象:

var words = ['robbery', 'murderer', 'housebreaking', 'car accident'];

function getAllIncidents( incidents ) {
  var re = new RegExp('('+ words.join('|') +')', 'i')
    , result = {};
  incidents.forEach(function( txt ) {
    var match = ( re.exec( txt ) || [,0] )[1];
    match && (result[ match ] = ++result[ match ] || 1);
  });
  return result;
}

console.log( getAllIncidents( incidents ) );
//^= { housebreaking: 1, car accident: 2, robbery: 1, murderer: 2 }

这更像是一个快速原型,但可以使用复数和多个关键字进行改进。

演示: http://jsbin.com/idesoc/1/edit

答案 6 :(得分:1)

是的,这是一种方法,虽然将普通单词与正则表达式匹配有点过分 - 在这种情况下,你应该使用indexOf as rbtLong suggested

你可以通过以下方式进一步完善它:

  • 附加i标志(匹配小写和大写字符)。
  • 为您的表达添加可能的单词变体。 robbery可以翻译成robber(y|ies),从而匹配单词的单数和复数变体。 car accident可以是(car|truck|vehicle|traffic) accident

字边界\ b

不要使用它。它需要在匹配的单词周围加上非字母数字字符,以防止匹配拼写错误。你应该尽可能地提出疑问。


if (incident.match(/(car|truck|vehicle|traffic) accident/i)) {
    trafficAccidents += 1;
}
else if (incident.match(/robber(y|ies)/i)) {
    robberies += 1;
}

注意我是如何丢弃g标志的;它代表“全局匹配”并使解析器在第一次匹配后继续搜索字符串。这似乎是不必要的,因为只有一个确认的事件足以满足您的需求。

本网站提供了对正则表达式的精彩介绍

http://www.regular-expressions.info/tutorial.html