Задать вопрос
@Johnick

Как обернуть в теги некоторые слова в HTML?

Есть переменная с html разметкой. Необходимо написать регулярное выражение для «обертывания» слов и фраз из подготовленного массива. Но нужно из данного выражения исключить теги с определенными классами или как-то избежать дублирования (подробнее ниже).
Например . Есть html
<div>
<span style="font-size:12px;">
<strong>Второе правило</strong> - надо действовать. Вместо того, чтобы жаловаться на абсурдность  мира, 
постараемся преобразить тот уголок, куда забросила нас судьба.
</span>
</div>

Есть массив со словами:
['правило', 'мир', 'уголок']

После замены должно получиться следующее:
<div>
<span style="font-size:12px;">
<strong>Второе <span class="glossary-term" data-toggle="tooltip" data-placement="right" title="тут подсказка">правило</span></strong> - надо действовать. 
Вместо того, чтобы жаловаться на абсурдность  мира, постараемся преобразить тот <span class="glossary-term" data-toggle="tooltip" data-placement="right" title="тут подсказка">уголок</span>, 
куда забросила нас судьба.
</span>
</div>


При помощи такой регулярки, частично это получилось сделать, но осталось пара проблем:
new RegExp(`(?<!<[^>]*?)(${word}\\S*)(?<!<[^>]*?)`, 'ig')

1. В массиве слово «мир», но при использовании этой регулярки, заменяются все слова, в которых есть «мир» (в тексте «мира»). Нужно чтобы замена происходила, только при полном совпадении.
2. Если в атрибуте title присутствует слово из массива, то происходит повторное «оборачивание» в этот тег.

function f(text) {
    let newText = text.html();
    let array = ['правило', 'мир', 'уголок'];
    array.forEach(word=> {
        let regex = new RegExp(`(?<!<[^>]*?)(${word}\\S*)(?<!<[^>]*?)`, 'ig');
        newText = newText.replace(regex, `<span class="hint" data-toggle="tooltip"
             data-placement="right" title="тут подсказка">$1</span>`);
    })
    return newText;
}


Как можно доработать эту регурярку или может есть другие решения данной задачи?
  • Вопрос задан
  • 445 просмотров
Подписаться 1 Простой Комментировать
Решения вопроса 1
sergiks
@sergiks Куратор тега JavaScript
♬♬
Попробовал сделать через DocumentFragment, рекурсивный обход текстовых Node
и обёртку найденных слов с помощью Range.surroundContents()

Получилось как-то переусложнённо. Но наверное лучше, чем регуляркой HTML разбирать: не станет менять слова в атрибутах тегов. Раз уж это разметка, можно работать с DOM.
Слабое место – не обошлось без регулярного выражения для поиска слов. Т.к. там кириллица, привычные \b для границы слова не работают, пришлось заглядывать впрёд-назад, и регулярка вышла некороткая.

Криво-длинно, но работает:

Из исходного HTML делается DocumentFragment — как DOM полноценного документа. Перебираются его узлы. Если узел не-текстовый, рекурсивно перебираем его дочерние узлы.
В текстовых узлах ищем искомые слова.

Найденное слово (по одному за раз) заменяется на обёртку с этим словом.
Вместо 1 исходного текстового узла, у нас становится уже 3: текст-элемент-текст.
Далее поиск повторяется с хвостовым остатком текста – третьим (текстовым) узлом, пока в тексте не останется искомых слов для замены.

Решение не лаконичное и не простое. Если возникнут вопросы, пишите, постараюсь объяснить.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы