【问题标题】:Case insensitive string replacement in JavaScript?JavaScript中不区分大小写的字符串替换?
【发布时间】:2010-09-21 19:14:12
【问题描述】:

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

例如:

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

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

最简单的方法是什么?

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

【问题讨论】:

    标签: javascript string replace case-insensitive


    【解决方案1】:

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

    这是一个用于 javascript (source) 的函数:

    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>");
    }
    

    【讨论】:

    • 您根本不应该为此使用正则表达式。您可以将'gi' 标志作为第三个参数传递给replace。您不必使用preg_quote 或创建RegExp 或任何类似的东西。
    • String.replace 中确实有一个“flags”方法,但它是非标准的,因此不可靠。最好的方法是制作一个“聚填充”方法,可选择适当的选项。 span>
    • @YellowAfterlife 标志在这里传递给正则表达式,而不是 String.replace 函数,所以没关系:)
    【解决方案2】:
    function highlightWords( line, word )
    {
         var regex = new RegExp( '(' + word + ')', 'gi' );
         return line.replace( regex, "<b>$1</b>" );
    }
    

    【讨论】:

    • 当然,您需要注意要替换的内容以及要搜索的内容,如@bobince 注释。如果您小心引用您的正则表达式字符,上述内容将适用于纯文本和大多数搜索......
    • 如果被替换的单词中有正则表达式字符,这将遇到麻烦。 @okoman 的解决方案解决了这个问题。
    • 如果作品是点或句点,这不起作用,如何使它在点或句点或多个句点的情况下工作(例如:“...”)
    • @helpme 这些是正则表达式中的特殊字符。您需要先使用反斜杠引用它们。请注意,反斜杠也是字符串中的引号字符,因此您需要在替换字符串中使用两个。 word.replace(/\./g, '\\.')
    【解决方案3】:

    您可以使用为您执行特殊字符转义的函数来增强 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>");
    }
    

    【讨论】:

    • ?在 javascript RegExp 中需要使用双反斜杠进行转义,例如 \\?
    • @Jerinaw 你认为我的RegExp.escape 函数有什么作用?
    • stackoverflow.com/questions/889957/… 我遇到了问号需要用双 \ 转义的问题,但我猜在 [] 中你不需要转义它。
    • @Jerinaw 实际上,您只需要为正则表达式转义一次问号,因此当您使用正则表达式文字时,您最终会得到 \?。但是您需要为 JS 字符串转义反斜杠 itself,因此当您从字符串构建正则表达式时,您最终会得到 \\?。是的,在字符类中,您真正必须转义的唯一字符是]
    • 请不要鼓励在 javascript 中进行猴子修补
    【解决方案4】:

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

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

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

    而且您不能完全确定哪些字符需要转义,因为并非每个浏览器的正则表达式实现都保证完全相同。 (特别是,较新的浏览器可能会添加新功能。)不特殊的反斜杠转义字符不能保证仍然有效,尽管实际上它确实有效。

    因此,您能做的最好的事情之一是:

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

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

    【讨论】:

      【解决方案5】:

      这样的事情怎么样:

      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");
      

      【讨论】:

        【解决方案6】:

        对于那些患有失调症或正则恐惧症的穷人:

        function replacei(str, sub, f){
        	let A = str.toLowerCase().split(sub.toLowerCase());
        	let B = [];
        	let x = 0;
        	for (let i = 0; i < A.length; i++) {
        		let n = A[i].length;
        		B.push(str.substr(x, n));
        		if (i < A.length-1)
        			B.push(f(str.substr(x + n, sub.length)));
        		x += n + sub.length;
        	}
        	return B.join('');
        }
        
        s = 'Foo and FOO (and foo) are all -- Foo.'
        t = replacei(s, 'Foo', sub=>'<'+sub+'>')
        console.log(t)

        输出:

        <Foo> and <FOO> (and <foo>) are all -- <Foo>.
        

        【讨论】:

          【解决方案7】:

          为什么不在每次调用您的函数时创建一个新的正则表达式?您可以使用:

          new Regex([pat], [flags])
          

          其中 [pat] 是模式的字符串,[flags] 是标志。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-03-01
            • 2014-04-11
            • 1970-01-01
            • 2012-02-08
            • 2013-03-14
            • 1970-01-01
            相关资源
            最近更新 更多