Замена строки без учета регистра в JavaScript?

мне нужно выделить, без учета регистра, данные ключевые слова в строке JavaScript.

например:

  • highlight("foobar Foo bar FOO", "foo") должен возвратить "<b>foo</b>bar <b>Foo</b> bar <b>FOO</b>"

мне нужен код для работы с любым ключевым словом и, следовательно, с помощью жестко закодированного регулярного выражения, такого как /foo/i не является достаточным решением.

какой самый простой способ сделать это?

(Это пример более общей проблемы, подробно описанной в названии, но я чувствую, что лучше всего обратиться к конкретному, полезному примеру.)

7 ответов


вы can используйте регулярные выражения при подготовке строки поиска. В PHP, например, есть функция preg_quote, которая заменяет все regex-символы в строке их экранированными версиями.

вот такая функция для javascript:

function preg_quote( str ) {
    // http://kevin.vanzonneveld.net
    // +   original by: booeyOH
    // +   improved by: Ates Goral (http://magnetiq.com)
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   bugfixed by: Onno Marsman
    // *     example 1: preg_quote("");
    // *     returns 1: '$40'
    // *     example 2: preg_quote("*RRRING* Hello?");
    // *     returns 2: '\*RRRING\* Hello\?'
    // *     example 3: preg_quote("\.+*?[^]$(){}=!<>|:");
    // *     returns 3: '\\.\+\*\?\[\^\]$\(\)\{\}\=\!\<\>\|\:'

    return (str+'').replace(/([\\.\+\*\?\[\^\]$\(\)\{\}\=\!\<\>\|\:])/g, "\");
}

(взято из http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_preg_quote/ )

таким образом, вы можете сделать следующее:

function highlight( data, search )
{
    return data.replace( new RegExp( "(" + preg_quote( search ) + ")" , 'gi' ), "<b></b>" );
}

function highlightWords( line, word )
{
     var regex = new RegExp( '(' + word + ')', 'gi' );
     return line.replace( regex, "<b></b>" );
}

вы можете улучшить объект 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></b>");
}

регулярные выражения хороши, пока ключевые слова действительно слова, вы можете просто использовать конструктор RegExp вместо литерала для создания одного из переменных:

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

трудность возникает, если "ключевые слова" могут иметь пунктуацию, поскольку пунктуация имеет особое значение в регулярных выражениях. К сожалению, в отличие от большинства других языков/библиотек с поддержкой regexp, в JavaScript нет стандартной функции для избежания пунктации для регулярных выражений.

и вы не можете быть полностью уверен, что именно символы нуждаются в экранировании, потому что не каждая реализация браузера regexp гарантированно будет точно такой же. (В частности, новые браузеры могут добавлять новые функции.) И обратные косые черты-экранирующие символы, которые не являются особенными, не гарантируют, что все еще будут работать, хотя на практике это происходит.

Так что лучшее, что вы можете сделать, это один из:

  • попытка поймать каждый специальный символ в общем браузере использовать сегодня [add: see Sebastian's рецепт]
  • обратная косая черта-избежать всех не буквенно-цифровых. care: \W также будет соответствовать символам Unicode не ASCII, которые вы действительно не хотите.
  • просто убедитесь, что в ключевом слове нет не буквенно-цифровых символов перед поиском

Если вы используете это, чтобы выделить слова в 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");

для тех бедных с disregexia или regexophobia:

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>.

почему бы просто не создать новое регулярное выражение при каждом вызове функции? Вы можете использовать:

new Regex([pat], [flags])

где [pat] - строка для шаблона, а [flags] - флаги.