Подтвердить что ты не робот

Неверная замена строки в JavaScript?

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

Например:

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

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

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

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

4b9b3361

Ответ 1

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

Вот такая функция для 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("$40");
    // *     returns 1: '\$40'
    // *     example 2: preg_quote("*RRRING* Hello?");
    // *     returns 2: '\*RRRING\* Hello\?'
    // *     example 3: preg_quote("\\.+*?[^]$(){}=!<>|:");
    // *     returns 3: '\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:'

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

(взято из 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>$1</b>" );
}

Ответ 2

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

Ответ 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>");
}

Ответ 4

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

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

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

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

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

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

Если вы используете это, чтобы выделить слова в HTML, которые уже имеют разметку, у вас проблемы. Ваше слово может отображаться в имени элемента или значении атрибута, и в этом случае попытка обернуть <b> вокруг него вызовет раскол. В более сложных сценариях возможно даже инъекция HTML в дыру безопасности XSS. Если вам нужно справиться с разметкой, вам понадобится более сложный подход, разделяющий '<... > , прежде чем пытаться обрабатывать каждый фрагмент текста самостоятельно.

Ответ 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)

Ответ 7

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

new Regex([pat], [flags])

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