JavaScript 中不区分大小写的字符串替换?

IT技术 javascript string replace case-insensitive
2021-01-13 14:54:05

我需要突出显示 JavaScript 字符串中给定的关键字,不区分大小写。

例如:

  • highlight("foobar Foo bar FOO", "foo") 应该回来 "<b>foo</b>bar <b>Foo</b> bar <b>FOO</b>"

我需要代码适用于任何关键字,因此使用硬编码的正则表达式 like/foo/i不是一个足够的解决方案。

什么是最简单的方法来做到这一点?

(这是标题中详述的更一般问题的一个实例,但我觉得最好用一个具体的、有用的例子来解决。)

6个回答

可以,如果你准备搜索字符串使用正则表达式。例如,在 PHP 中有一个函数 preg_quote,它将字符串中的所有正则表达式字符替换为其转义版本。

这是 javascript 的这样一个函数(源代码):

function preg_quote (str, delimiter) {
  //  discuss at: https://locutus.io/php/preg_quote/
  // original by: booeyOH
  // improved by: Ates Goral (https://magnetiq.com)
  // improved by: Kevin van Zonneveld (https://kvz.io)
  // improved by: Brett Zamir (https://brett-zamir.me)
  // bugfixed by: Onno Marsman (https://twitter.com/onnomarsman)
  //   example 1: preg_quote("$40")
  //   returns 1: '\\$40'
  //   example 2: preg_quote("*RRRING* Hello?")
  //   returns 2: '\\*RRRING\\* Hello\\?'
  //   example 3: preg_quote("\\.+*?[^]$(){}=!<>|:")
  //   returns 3: '\\\\\\.\\+\\*\\?\\[\\^\\]\\$\\(\\)\\{\\}\\=\\!\\<\\>\\|\\:'

  return (str + '')
    .replace(new RegExp('[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\' + (delimiter || '') + '-]', 'g'), '\\$&')
}

因此,您可以执行以下操作:

function highlight(str, search) {
    return str.replace(new RegExp("(" + preg_quote(search) + ")", 'gi'), "<b>$1</b>");
}
您根本不应该为此使用 RegExp。您可以将'gi'标志作为第三个参数传递给replace. 您不必使用preg_quote或创建 aRegExp或任何类似的东西。
2021-04-08 14:54:05
@YellowAfterlife 标志在这里传递给正则表达式,而不是传递给 String.replace 函数,所以没问题:)
2021-04-08 14:54:05
String.replace 中确实有一个“flags”方法,但它是非标准的,因此不可靠。The best approach would be to make a "polyfill" method that selects an appropriate option.
2021-04-11 14:54:05
function highlightWords( line, word )
{
     var regex = new RegExp( '(' + word + ')', 'gi' );
     return line.replace( regex, "<b>$1</b>" );
}
@helpme 那些是正则表达式中的特殊字符。您需要先使用反斜杠引用它们。请注意,反斜杠也是字符串中的引号字符,因此您需要在替换字符串中使用两个。 word.replace(/\./g, '\\.')
2021-03-17 14:54:05
如果要替换的单词中有正则表达式字符,这将遇到麻烦。@okoman 的解决方案解决了这个问题。
2021-03-22 14:54:05
当然,您需要小心您要替换的内容以及您在@bobince 注释中搜索的内容。如果您小心地引用正则表达式字符,则上述内容适用于纯文本和大多数搜索...
2021-03-31 14:54:05
如果工作是点或句点,则这不起作用,如何在点或句点或多个句点的情况下使其工作(例如: "..." )
2021-04-06 14:54:05

您可以使用为您执行特殊字符转义的函数来增强 RegExp 对象:

RegExp.escape = function(str) 
{
  var specials = /[.*+?|()\[\]{}\\$^]/g; // .*+?|()[]{}\$^
  return str.replace(specials, "\\$&");
}

然后你就可以毫无顾虑地使用其他人的建议:

function highlightWordsNoCase(line, word)
{
  var regex = new RegExp("(" + RegExp.escape(word) + ")", "gi");
  return line.replace(regex, "<b>$1</b>");
}
stackoverflow.com/questions/889957/...我遇到过问号需要用双 \ 转义的问题,但我想在 [] 中你不需要转义它。
2021-03-20 14:54:05
请不要鼓励在 javascript 中进行猴子修补
2021-03-24 14:54:05
? 在 javascript RegExp 中需要用双反斜杠转义,如 \\?
2021-04-04 14:54:05
@Jerinaw 你认为我的RegExp.escape功能是什么?
2021-04-07 14:54:05
@Jerinaw实际上,您只需要为正则表达式转义一次问号,因此您最终\?会使用正则表达式文字。但是您需要为 JS 字符串转义反斜杠本身,因此\\?当您从字符串构建正则表达式时,您最终会得到结果。是的,在字符类中,您真正必须转义的唯一字符].
2021-04-09 14:54:05

只要关键字是真正的单词,正则表达式就很好,您可以只使用 RegExp 构造函数而不是文字来从变量创建一个:

var re= new RegExp('('+word+')', 'gi');
return s.replace(re, '<b>$1</b>');

如果“关键字”可以包含标点符号,则会出现困难,因为标点符号在正则表达式中往往具有特殊含义。不幸的是,与大多数其他支持 regexp 的语言/库不同,JavaScript 中没有标准函数来为 regexp 转义标点。

而且您不能完全确定到底哪些字符需要转义,因为并非每个浏览器的 regexp 实现都保证完全相同。(特别是,较新的浏览器可能会添加新功能。)并不能保证非特殊的反斜杠转义字符仍然有效,尽管在实践中确实如此。

因此,您可以做的最好的事情是:

  • 尝试捕捉当今常见浏览器使用中的每个特殊字符 [添加:请参阅 Sebastian 的食谱]
  • 反斜杠转义所有非字母数字。注意: \W 也将匹配您并不真正想要的非 ASCII Unicode 字符。
  • 在搜索之前确保关键字中没有非字母数字

但是,如果您使用它来突出显示 HTML 中已经有标记的单词,那么您就会遇到麻烦。您的“单词”可能出现在元素名称或属性值中,在这种情况下,尝试用 < b> 包裹它会导致损坏。在更复杂的场景中,甚至可能是对 XSS 安全漏洞的 HTML 注入。如果您必须处理标记,您将需要一种更复杂的方法,在尝试单独处理每一段文本之前分离出 '< ... >' 标记。

像这样的事情怎么样:

if(typeof String.prototype.highlight !== 'function') {
  String.prototype.highlight = function(match, spanClass) {
    var pattern = new RegExp( match, "gi" );
    replacement = "<span class='" + spanClass + "'>$&</span>";

    return this.replace(pattern, replacement);
  }
}

然后可以这样调用:

var result = "The Quick Brown Fox Jumped Over The Lazy Brown Dog".highlight("brown","text-highlight");