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

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

Например:

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

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

Как это сделать проще всего?

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

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
54
0
56 513
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Ответ принят как подходящий

Вы может используете регулярные выражения, если вы готовите строку поиска. Например, в 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 или создавать RegExp или что-то в этом роде.

Nathan Wall 24.01.2013 07:39

В String.replace действительно есть метод «flags», но он нестандартный, а значит, ненадежный. Лучшим подходом было бы создание метода «полифил», который выбирает подходящий вариант.

YellowAfterlife 24.05.2014 17:18

@YellowAfterlife Здесь флаги передаются регулярному выражению, а не функции String.replace, так что все в порядке :)

Mike Gleason jr Couturier 20.01.2016 02:12

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

new Regex([pat], [flags])

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

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

Конечно, вам нужно быть осторожным с тем, что вы заменяете и что ищете в заметках @bobince. Вышеупомянутое будет хорошо работать для обычного текста и большинства поисков, если вы осторожно цитируете свои символы регулярного выражения ...

tvanfosson 11.11.2008 16:24

Это вызовет проблемы, если в заменяемом слове есть символы регулярного выражения. Решение @koman обходит это.

Herb Caudill 21.08.2009 19:46

Это не работает, если работа является точкой или точкой, как заставить ее работать в случае точки или точки, или нескольких точек (например: "...")

Santosh 23.05.2016 12:37

@helpme - это специальные символы в регулярном выражении. Вам нужно сначала процитировать их, используя обратную косую черту. Обратите внимание, что обратная косая черта также является символом кавычек в строке, поэтому вам нужно использовать два в строке замены. word.replace(/\./g, '\\.')

tvanfosson 23.05.2016 15:58

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

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

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

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

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

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

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

Вы можете улучшить объект 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 22.03.2013 19:49

@Jerinaw Как вы думаете, что делает моя функция RegExp.escape?

Tomalak 22.03.2013 20:13
stackoverflow.com/questions/889957/… Я столкнулся с проблемами, когда вопросительный знак нужно было экранировать двойным \, но я думаю, что в [] вам не нужно его экранировать.
Jerinaw 16.04.2013 06:43

@Jerinaw Фактически, вам нужно избегать вопросительного знака только один раз для регулярного выражения, поэтому вы получите \?, когда используете литерал регулярного выражения. Но вам нужно избегать обратной косой черты сам для строк JS, поэтому вы получите \\? при построении регулярного выражения из строки. И да, в классе символов единственный символ, который вы действительно избегаете с помощью должен, - это ].

Tomalak 16.04.2013 09:26

пожалуйста, не поощряйте исправление обезьян в javascript

Damon 16.01.2020 23:37

Как насчет чего-то вроде этого:

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

Для бедных с дисрегексией или регексофобией:

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.info(t)

Выход:

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

Другие вопросы по теме