JavaScript:高亮子字符串,保留原始大小写但在不区分大小写模式下搜索

40

我正在尝试编写一个“建议搜索框”,但我找不到一种允许使用javascript突出显示子字符串并保留原始大小写的解决方案。

例如,如果我搜索“ca”,我会在服务器端以不区分大小写的方式进行搜索,并获得以下结果:

计算器

日历

ESCAPE

我想在所有先前的单词中查看搜索字符串,因此结果应为:

Calculator

calendar

ESCAPE

我尝试了以下代码:

var reg = new RegExp(querystr, 'gi');
var final_str = 'foo ' + result.replace(reg, '<b>'+querystr+'</b>');
$('#'+id).html(final_str);

但很明显,这样我会失去原来的大小写!

有没有解决这个问题的方法?


https://markjs.io/ - ControlAltDel
9个回答

77

.replace()的第二个参数中使用一个函数,该函数返回带有连接标签的实际匹配字符串。

试一下:http://jsfiddle.net/4sGLL/

reg = new RegExp(querystr, 'gi');
       // The str parameter references the matched string
       //    --------------------------------------v
final_str = 'foo ' + result.replace(reg, function(str) {return '<b>'+str+'</b>'});
$('#' + id).html(final_str);​

JSFiddle示例及其输入:https://jsfiddle.net/pawmbude/


13
最好的方法,尽管我会不使用函数完成它:result.replace(reg, '<b>$&</b>')。不过我不确定性能如何,只是看起来更好一些。 - Joost
我也不知道,但我总是忘记function的语法,所以我去找了一些文档。我偶然发现了这个。 - Joost
请记住,如果您想在字符串中匹配字母的任何位置,例如,如果用户键入“js”,并且您想要在“JavaScript”中单独突出显示它们,则此方法将无法正常工作。 在这种情况下,您必须逐个检查每个字母。 - jdunning
2
这并没有处理正确的转义。 - rosenfeld
2
以上情况无法处理特殊字符跳过。例如:https://jsfiddle.net/40wfnx3z/ 如果您搜索文本“test(123)”,它将抛出错误“Uncaught Syntax Error: Invalid regular expression: /test(/: Unterminated group”,并且高亮功能也会中断。请添加这些功能,那么此解决方案将成为完整的答案。 - VIJAY P
要转义特殊字符,请参考此链接:https://dev59.com/OHA75IYBdhLWcg3wJFmY - rrebase

16

ES6 版本

const highlight = (needle, haystack) =>
  haystack.replace(
      new RegExp(needle, 'gi'),
      (str) => `<strong>${str}</strong>`
  );

嘿,你能否请检查一下这个链接 https://dev59.com/tarka4cB1Zd3GeqPXAEe?noredirect=1#comment85842606_49420541? - ganesh
这会转义HTML并匹配文本吗? - Kaushik Thanki

1
虽然到目前为止其他答案看起来很简单,但它们在许多真实情况下并不能真正使用,因为它们没有处理适当的文本 HTML 转义和 RegExp 转义。如果您想要突出显示每个可能的片段,并正确转义文本,像这样的函数将返回您应该添加到建议框中的所有元素:
function highlightLabel(label, term) {
  if (!term) return [ document.createTextNode(label) ]
  const regex = new RegExp(term.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&'), 'gi')
  const result = []
  let left, match, right = label
  while (match = right.match(regex)) {
    const m = match[0], hl = document.createElement('b'), i = match.index
    hl.innerText = m
    left = right.slice(0, i)
    right = right.slice(i + m.length)
    result.push(document.createTextNode(left), hl)
    if (!right.length) return result
  }
  result.push(document.createTextNode(right))
  return result
}

你至少应该检查一下你要发布的代码。createTextNode未定义(是document.createTextNode吗?)b未定义,是hl吗? - gerasalus

1
很好的结果与。
function str_highlight_text(string, str_to_highlight){
   var reg = new RegExp(str_to_highlight, 'gi');
   return string.replace(reg, function(str) {return '<span style="background-color:#ffbf00;color:#fff;"><b>'+str+'</b></span>'});
}

由于用户113716的帮助,编程变得更加容易记忆...感谢https://dev59.com/WnA75IYBdhLWcg3wdIl0#3294644

0

string.replace在一般情况下会失败。如果您使用.innerHTML,replace可以替换标签中的匹配项(如a标签)。如果您使用.innerText或.textContent,则会删除先前在HTML中存在的任何标记。更重要的是,在这两种情况下,如果您想要删除突出显示,则会损坏您的HTML。

真正的答案是mark.js(https://markjs.io/)。我刚发现了这个 - 这就是我长期以来一直在寻找的东西。它正是您想要的。


-1

高亮搜索词并锚定到第一次出现-开始

function highlightSearchText(searchText) {
    var innerHTML = document.documentElement.innerHTML;
    var replaceString = '<mark>'+searchText+'</mark>';
    var newInnerHtml = this.replaceAll(innerHTML, searchText, replaceString);
    document.documentElement.innerHTML = newInnerHtml;
    var elmnt = document.documentElement.getElementsByTagName('mark')[0]
    elmnt.scrollIntoView();
}

function replaceAll(str, querystr, replace) {
    var reg = new RegExp(querystr, 'gi');
    var final_str = str.replace(reg, function(str) {return '<mark>'+str+'</mark>'});
    return final_str
}

突出显示搜索词并锚定到第一次出现 - 结束


-1

我找到了一种更简单的方法来实现它。JavaScript正则表达式可以记住它匹配的字符串。这个特性可以在这里使用。

我稍微修改了代码。

reg = new RegExp("("+querystr.trim()+")", 'gi');
final_str = 'foo ' + result.replace(reg, "<b>&1</b>");
$('#'+id).html(final_str);

你能否添加一些关于你的解决方案和被接受答案之间差异的描述?以及 ")" 的实用性是什么? - Mimouni

-1

.match()执行不区分大小写的匹配,并返回一个保留大小写的匹配数组。

var matches = str.match(queryString),
    startHere = 0,
    nextMatch,
    resultStr ='',
    qLength = queryString.length;

for (var match in matches) {
    nextMatch = str.substr(startHere).indexOf(match);
    resultStr = resultStr + str.substr(startHere, nextMatch) + '<b>' + match + '</b>';
    startHere = nextMatch + qLength;
}

-1

我做的事情完全一样。

你需要复制一份。

我在数据库中存储了一个真实字符串的副本,全部转换为小写。

然后,我使用小写版本的查询字符串进行搜索或执行不区分大小写的正则表达式。

然后,在主字符串中使用找到的起始索引加上查询字符串的长度来突出显示结果中的查询字符串。

由于查询字符串的大小写不确定,因此不能在结果中使用它。您需要突出显示原始字符串的一部分。


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