使用正则表达式和替换强调字符串中的多个关键字

时间:2015-04-13 17:34:38

标签: javascript regex

我有一个带有字符串属性的对象数组,我使用正则表达式搜索多个关键字。例如,如果集合看起来像这样

collection = [
    {searchString: 'Troarn Lower Normandy France'},
    {searchString: 'Tröbitz Brandenburg Germany'},
    {searchString: 'Tröbnitz Thuringia Germany'},
    {searchString: 'Tröchtelborn Thuringia Germany'},
    {searchString: 'Trochtelfingen Baden-Württemberg Germany'},
    {searchString: 'Trockenborn-Wolfersdorf Thuringia Germany'},
    {searchString: 'Trodena Trentino-Alto Adige Italy'},
    {searchString: 'Trodica The Marches Italy'},
    {searchString: 'Trofaiach Styria Austria'},
    {searchString: 'Trofarello Piedmont Italy'}
];

我有一个文本字符串可以像这样搜索

text = 'tro france';

我通过拆分文本来获取关键字

keywords = text.split(' ');

然后从这些关键字

构建一个正则表达式
regex = '';
for (i = 0; i < keywords.length; i++ ) {
    if (keywords[i] !== "" && keywords[i] !== undefined) {
        regex += "(?=(^|.*\\s)" + keywords[i] + ")";
    }
}
regex = new RegExp(regex, "i");

所以文字'tro france'会给这个正则表达式/(?=(^|.*\s)tro)(?=(^|.*\s)france)/i 并将匹配集合中的第一个项目。 我会像这样搜索这个集合

for (i = 0; i < collection.length; i++) {
    if (collection[i].searchString.search(regex) !== -1) {

        // ... do stuff here

    }
}

但现在我想强调搜索字符串中的关键字。 例如,如果文字是“法国”。我想要的话是&#39; tro&#39; 和法国&#39;在我显示结果的地方加下划线。我可以做这个 以一种简单的方式,但我不知道如何做多个匹配和 更换。我已经有一个,但只有我不做才有效 空格并跳转到其他关键字。

例如,如果文字很简单,那么&#34;非跳跃&#34;但像'Troarn Lo'这样的直接比赛然后我可以像这样替换它

emphasized = new RegExp('('+text+'.*?)', 'i');
emphasized = collection[i]searchString.replace(emphasized, '<em>$1</em>');

但我在多个关键字部分完全空白。

所以,如果文本是'Tro Lo Nor Fra',我可以将集合中的第一项与正则表达式匹配,但在此之后,我想强调这些关键字,就像我上面所做的那样,除了所有关键字

我怎样才能做到这一点?

3 个答案:

答案 0 :(得分:1)

您可以将所有关键字组合到一个正则表达式中。请注意,这将使g标志成为强制性的。

emphasized = new RegExp(keywords.join('|'), 'ig');
emphasized = collection[i].searchString.replace(emphasized, '<em>$&</em>');

请注意,这会突出显示每个每个关键字的出现次数。另外,请使用<mark>代替<em>。当与RegExp一起使用时,关键字应该被转义。

答案 1 :(得分:0)

以下答案取决于您/想要支持的浏览器。所有新的浏览器都支持它,但可能在旧的IE中给你带来问题(我没有找到确切的compat信息)。

您也可以使用String.prototype.indexOf,而不是笨拙的正则表达式。 它的缺点是具有初始字符串的保证顺序 *,但它具有以下优点:

  • 它不使用慢速正则表达式
  • 它会返回索引,其中显示实际的搜索字符串,为您提供将标记插入到这些位置的机会
  • 它能够返回&#34; partial&#34;点击(例如&#34;这些结果与您的三个搜索结果中的两个匹配&#34;):

您的修改示例:

keywords = text.split(' ');

for (var i = 0; i < collection.length; i++) {
    for (var j = 0; j < keywords.length; j++) {
        var position = collection[i].indexOf(keywords[j]);
        if (position !== -1) {
           /* keyword[j] has been found at [position], so you could do: */

           // insert "<em>" markup into string at [position]
           // increase the matchcounter by 1
        }
    }
}
// show results according to matchcounter, e.g. full match only
// (matchcounter === keywords.length)

编辑:*实际上,您可以使用第二个参数位置从上次点击的位置开始搜索。

答案 2 :(得分:0)

以下是我将这样做的方式:

var query = 'tro  al it';

// first we extract the terms from the query and we normalize them:
var corr = {
    'ae':'(?:ae|æ)', 'oe':'(?:oe|œ)',
    'ss':'(?:ss|ß)', 'ß':'(?:ß|ss)',
    'a':'[aàâä]', 'e':'[eéèêë]', 'i':'[iîï]', 'o':'[oôö]', 'u':'[uûü]',
    'c':'[cç]', 'y':'[yÿ]' }; // need to be completed

var terms = query.toLowerCase()
    .replace(/(?=[aeiyoucs])(?:[ao]e?|[eiuçy]|ss)/g, function (m) {
        return corr[m];
     }).split(/\s+/);

// now we build patterns to be able to filter or to find:
var testPatterns = terms.map(function (item) {
   return new RegExp('(?:^|[- \'])' + item, 'i');
});
var HLPattern = new RegExp('(^|[- \'])(' + terms.join('|') + ')', 'ig');

// usage:
var results = collection;

// to filter the results:
testPatterns.forEach(function(pattern) { 
    results = results.filter(function (item) {
        return pattern.test(item.searchString);
    });
});

// to highlight the results:
results = results.map(function (item) {
    item.searchString = item.searchString.replace(HLPattern, '$1<em>$2</em>');
    return item;
});