Javascript RegExp заменить текст между двумя тегами, если открывающий тег имеет указанный класс - PullRequest
0 голосов
/ 19 февраля 2019

У меня есть следующий HTML-код:

<span class="whatever-class custom-class-name" attribute="Whatever 1 AAA">AAA BBB</span>
<span class="search-text custom-class-name" attribute="Whatever 2 AAA">Text AAA</span>

Я хочу заменить текст между тегами span, но только если тег span имеет класс " search-text ",Так что в моем случае у меня есть строка, содержащая HTML-код с двумя пролетами.Я хочу заменить текст из второго интервала, если он содержит искомый текст.

Я ищу: " aa " и хочу заменить его на <span class="highlight-text">aa</span>.Таким образом, конечный результат должен быть:

<span class="whatever-class custom-class-name" attribute="Whatever 1 AAA">AAA BBB</span>
<span class="search-text custom-class-name" attribute="Whatever 2 AAA">Text <span class="highlight-search">AA</span>A</span>

Сейчас я делаю что-то вроде:

var paint = $.proxy(this._paint, this);
var regex = /(<span class="search-text[^>]+>|<\/span>)/g;
item.node.innerHTML = item.html.replace(regex, paint);

, где " value " равно: "aa"и" item.html"- это HTML-код, представленный в начале моего вопроса.

функция _paint:

_paint: function($0) {
   return '<span class="highlight-text">' + $0 + '</span>';
},

На данный моментВ результате второй диапазон целиком заключен в '<span class="highlight-text">' + $0 + '</span>';.Вот результат:

<span class="whatever-class custom-class-name" attribute="Whatever 1 AAA">AAA BBB</span>
<span class="highlight-text"><span class="search-text custom-class-name" attribute="Whatever 2 AAA">Text AAA</span></span>

Я хочу, чтобы только текст соответствий был обернут внутри диапазона hghlight, например:

<span class="whatever-class custom-class-name" attribute="Whatever 1 AAA">AAA BBB</span>
<span class="search-text custom-class-name" attribute="Whatever 2 AAA">Text <span class="highlight-text">AA</span>A</span>

Есть идеи?Спасибо.

Ответы [ 2 ]

0 голосов
/ 19 февраля 2019

Частичное решение, вдохновленное ответом Даниэля Бека.Это решение не манипулирует DOM.(Я только что отобразил результат в DOM для демонстрационных целей)

https://jsfiddle.net/mt2yz90L/3/

HTML:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="result">
</div>

JS:

  let searchedText = 'aa';
  let html ='<span class="whatever-class custom-class-name" attribute="Whatever 1 AAA">AAA BBB</span><span class="search-text custom-class-name" attribute="Whatever 2 AAA">Text AAA</span> I';
  var htmlParts = html.split(/(<span class="search-text[^>]+>|<\/span>)/g);
  var htmlPartsIndex = 0;
  for(var i=0; i < htmlParts.length; i++) {
    if(htmlParts[i].indexOf('search-text') !== -1) {
        htmlPartsIndex = ++i;
      break;
    }
  }
  if(htmlPartsIndex > 0) {
     htmlParts[htmlPartsIndex] = htmlParts[htmlPartsIndex].toLowerCase().replace(searchedText, '<span class="highlight-text">' + searchedText + '</span>')
  }
  $('#result').html(htmlParts.join(''));

CSS:

.highlight-text {
  background-color: red;
}

Моя единственная проблема заключается в том, что в моем случае (более 300 элементов для анализа) он блокирует браузер.Так что это довольно медленно.Я написал это в мысли, что, возможно, кто-то поделится более быстрым решением.

0 голосов
/ 19 февраля 2019

Regex - это общеизвестно неправильный инструмент для большей части этой работы;он предназначен для манипулирования строками, а не структурированными данными, такими как HTML.К счастью, вы уже находитесь в браузере, поэтому у вас есть целый набор инструментов, предназначенных для манипулирования DOM: вы также можете его использовать.(Вы также пометили вопрос с помощью jQuery, что делает его еще проще.)

Обновление: я неправильно прочитал детали в вопросе и извлекал строку поиска из атрибута родительского узлавместо внешне;Я также не смог сделать поиск нечувствительным к регистру.Оба исправлены ниже:

// Make a case-insensitive regex from the search string
let str = 'aa';
let re = new RegExp(str, "gi");

// operate only on the .search-text nodes:
$('.search-text').each(function(i, el) {
  // get the current contents of the element:
  let text = $(el).html();

  // Add your highlights:
  text = text.replace(re, '<span class="highlight-text">$&</span>');

  // insert the modified text back into the DOM:
  $(el).html(text);
})
.highlight-text {
  background-color: #FFC
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span class="whatever-class custom-class-name" attribute="Whatever 1 AAA">AAA BBB</span>
<span class="search-text custom-class-name" attribute="Whatever 2 AAA">Text AAA</span> I

Это действительно безопасно, только если у элементов .search-text нет дочерних узлов. обычно будет работать, даже если они содержат некоторый HTML, но только если:

  • Вы уверены, что выделенные строки никогда не будут соответствовать частям самого HTML,и
  • нет никаких привязок событий, прикрепленных к элементам DOM (этот скрипт заменяет содержимое .search-text wholesale.)

Например, при попытке выделить слово "span "в HTML-строке, содержащей <span> элементов, приведет к недопустимому HTML:

// same script as above
$('.search-text').each(function(i, el) {
  let text = $(el).html();
  let highlights = $(el).attr("attribute").split(" ");
  for (str of highlights) {
    text = text.replace(str, '<span class="highlight-text">' + str + '</span>');
  }
  $(el).html(text);
})
.highlight-text {
  background-color: #FFC
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<span class="search-text" attribute="span">Text AAA <span>test</span></span>

Начиная со строки

Если отправной точкой является строка HTML вместо уже построенного дерева DOM, все, что вам нужнонужно сначала преобразовать эту строку во фрагмент документа, чтобы вы могли использовать на нем следующие инструменты DOM:

let fragment = $('<template>');
fragment.html($yourStringHere);
/* manipulate fragment contents as above, then */
return fragment.html();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...