Вставка тегов между содержимым html

У меня есть образец ниже содержимого в mydiv

<div id="mydiv">
   sample text sample text sample text...
   ......
   <i>inner text </i> <i>sample text </i>
   ......
   <b>sample text </b> <i>sample text </i>
</div>

Теперь я хочу добавить подсветку div между содержимым mydiv. образец приведен ниже.

<div class="highlight">highlight text</div>

Я хочу вставить этот div в каждые 200 слов, но проблема в том, что он не должен проходить внутри любого из тегов для детей. например, в случае, когда 200-е слово является внутренним, оно не должно добавляться как

<div id="mydiv">
   sample text sample text sample text...
   ......
   <i>inner<div class="highlight">highlight text</div> text </i> <i>sample text </i>
   ......
   <b>sample text </b> <i>sample text </i>
</div>

он должен добавляться после внутренних тегов

<div id="mydiv">
   sample text sample text sample text...
   ......
   <i>inner text </i> <div class="highlight">highlight text</div> <i>sample text </i>
   ......
   <b>sample text </b> <i>sample text </i>
</div>

Я попробовал с подстрокой, но он входит в дочерние теги. Есть ли способ достичь этого? Мы можем использовать любые js-библиотеки.

Ответ 1

Самый простой способ сделать это - прокрутить содержимое вашего div и вставить выделение в нужное место. Вот код:

$(document).ready(function () {
    // count of characters (modulo the period) and selected period
    var count = 0, period = 200;

    // iterator and highlight
    var words = '', highlight = '<div class="highlight">highlight text</div>';

    // loop through the contents
    $('#mydiv').contents().each(function () {
        // we only care about text contents
        if (this.nodeType === 3) {
            // get the individual words
            words = $(this).text().split(' ');
            // loop through them
            for (var j = 0; j < words.length; j++) {
                // increase count except if the word is empty (mutiple spaces)
                if (words[j] && words[j] !== '\n') { count++; }
                // if the period is exceeded, add the highlight and reset the count
                if (count === period) {
                    words.splice(1 + j++, 0, highlight);
                    count = 0;
                }
            }
            // replace the text
            $(this).replaceWith(words.join(' '));
        }
    });
});

Ответ 2

Вы можете использовать JQuery after или insertAfter, чтобы вставить элемент после цели.

append метод вставляет указанный контент как last child каждого элемента в коллекции jQuery

$(function(){
    
  // your logic to find position goes here...
  
  // append  text after an element 
  $("#mydiv i:first-child").after("<div class='highlight'>highlight text</div>");
  
});
.highlight{
   color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="mydiv">
  sample1 text1 sample1 text1 sample1 text1sample1 tex1 sample1 text1 sample text1 sample2 text2 sample2 text sample2 textsample2 text2 sample2 text2 sample2 text2 sample3 text3 sample3 text3 sample3 textsample3 text3 sample3 text3 sample3 text3 sample
  3 text 3sample 3text sample3 textsample3 text4 sample 4text sample4 text

  <i>1inner text 1 </i>  <i>sample text 1</i>
  <i>2inner text 2</i>  <i>sample text2 </i>
  <i>3inner text 3</i>  <i>sample text 3</i>
  <i>4inner text 4</i>  <i>sample text4 </i>
  <i>5inner text 5</i>  <i>sample text5 </i>
  <i>6inner text 6</i>  <i>sample text6 </i>
  <i>7inner text 7</i>  <i>sample text 7</i>

  <b>8sample text 8</b>  <i>sample text 8</i>
  <b>9sample text 9</b>  <i>sample text 9</i>
  <b>10sample text 10</b>  <i>sample text10 </i>
  <b>11sample text 11</b>  <i>sample text 11</i>
  <b>12sample text 12</b>  <i>sample text 12</i>

</div>

Ответ 3

ОБНОВЛЕНО Div, который я буду добавлять после каждого второго слова.

var some_div = '<div style="display:inline-block;color:red;">some_text</div>';

var text = $('#mydiv').text().match(/\w+/g);

Во-вторых, пройдите через все слова и префикс этих слов в html div с уникальным текстом идентификатора.

Здесь я добавляю строку <index>$$, где <index> увеличивается при каждом обходе.

var i = 1;
var count = 1;
var html = $('#mydiv').html();

text.forEach(function(word, index) {

  var offset = html.indexOf(word);
  while (html[offset - 1] == '$' && html[offset - 2] == '$') {
    offset = html.indexOf(word, offset + 1);
  }

  if ((count % up_index) == 0) {
    html = html.slice(0, offset) + (i++) + '$$' + html.slice(offset)
    $('#mydiv').html(html);
  }

  count++;
});

Наконец, пропустите все уникальные маркеры и замените их на html.

чтобы найти токены, используйте $('#mydiv').find(':contains(' + j + '$$)'); jquery.

for (var j = 1; j < i; j++) {
  var elm = $('#mydiv').find(':contains(' + j + '$$)');
  if (elm.length == 0) {
    console.log('inroot>>' + ':contains(' + j + '$$)');
    var offset = $(':contains(' + j + '$$)').last().html().indexOf(j + '$$');
    var t_html = $(':contains(' + j + '$$)').last().html().slice(0, (offset + (("" + j + '$$').length))).replace(/[0-9]\$\$/ig, '');
    t_html += some_div;
    t_html += $(':contains(' + j + '$$)').last().html().slice(offset + (("" + j + '$$').length));
    $('#mydiv').html(t_html);

  } else {
    console.log('not inroot>>' + ':contains(' + j + '$$)');
    $(some_div).insertAfter(elm.last());
  }
}

Вот пример, где я добавил div после каждого 2nd word

Во-первых, я извлекаю все слова внутри интересующего контейнера следующим образом:

var some_div = '<div style="display:inline-block;color:red;">some text</div>';

var up_index = 2; // Word index that will be updated every 2nd word.

var text = $('#mydiv').text().match(/\w+/g);

var i = 1;
var count = 1;
var html = $('#mydiv').html();

text.forEach(function(word, index) {

  var offset = html.indexOf(word);
  while (html[offset - 1] == '$' && html[offset - 2] == '$') {
    offset = html.indexOf(word, offset + 1);
  }

  if ((count % up_index) == 0) {
    html = html.slice(0, offset) + (i++) + '$$' + html.slice(offset)
    $('#mydiv').html(html);
  }

  count++;
});

for (var j = 1; j < i; j++) {
  var elm = $('#mydiv').find(':contains(' + j + '$$)');
  if (elm.length == 0) {
    console.log('inroot>>' + ':contains(' + j + '$$)');
    var offset = $(':contains(' + j + '$$)').last().html().indexOf(j + '$$');
    var t_html = $(':contains(' + j + '$$)').last().html().slice(0, (offset + (("" + j + '$$').length))).replace(/[0-9]\$\$/ig, '');
    t_html += some_div;
    t_html += $(':contains(' + j + '$$)').last().html().slice(offset + (("" + j + '$$').length));
    $('#mydiv').html(t_html);

  } else {
    console.log('not inroot>>' + ':contains(' + j + '$$)');
    $(some_div).insertAfter(elm.last());
  }
}

$('#mydiv').html($('#mydiv').html().replace(/[0-9]\$\$/ig, ''));
.highlight {
  color: red;
  display: inline-block;
}
b {
  background-color: blue;
}
i {
  background-color: yellow;
}
i,
b {
  border: 1px solid green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="mydiv">
  sample text
  <b><a>sample text</a></b>  <i>sample text </i>
  ......
  <i>inner text </i>  <i>sample text </i>
  ......
  <b>sample text </b>  <i>sample text </i>
</div>

Ответ 4

Вы не указали, как вы попадаете в текст внутри DOM (и я предполагаю, что вы используете DOM). Но с учетом текста node, содержащего интересующее слово, что-то подобное должно делать. Для удобства я использую минимальное количество jQuery, вряд ли это необходимо.

// use jQuery to find the text node "inner text" from your example
let textNode = $("#mydiv i")
    .first()
    .contents()
    .filter(function () {
        return this.nodeType == 3; /* text node */
    }).get(0);

// find the parent element of the text node
let el = textNode;
while (el.parentNode) {
    if (el.nodeType == 1) break; /* element */
    el = el.parentNode;
}
// append the html after the parent of the text node.
 $(el).after(`<div class="highlight">highlight text</div>`);

Вы можете увидеть это в действии на plnkr.

В основном код получает текст node N-го слова интереса, находит его родительский элемент, а затем вставляет желаемый html в качестве первого правого родственника родительского элемента.

Ответ 5

В любом случае, я надеюсь, что это поможет. ПРИМЕЧАНИЕ. В HTML используется образец контента.
Попробуйте разделить контент div и работайте с ним. См. Комментарии для объяснений:

        //1.Get mydiv content
        //2. Split spaces and newlines
        //3. Remove empty array values
        var div =     $("#mydiv").html().toString().split(/[\s+\n]/).filter(String);

        var allowAdd = true, appendNow;
        for(var a=0; a < div.length ; a++){
            if(div[a].match(/^</) && div[a].match(/>$/)){ //search for end tags ie. </i>, </b>
                if(div[a].match(/<\//)){ //if end tag, 
                    allowAdd = true;    //allow append
                }
            }else if (div[a].match(/</)){ //if start stag,
                allowAdd = false;   //disallow append (inside block)

            }

            if((a+1)%200 == 0){
                //every 200 words
                appendNow = true;
            }

            //append if 200th word and end tag is passed
            if(appendNow && allowAdd){
                div[a] += ' <div class="highlight">highlight text </div> ';
                appendNow = false;
            }
        }

        //join array values and assign value to mydiv content
        $("#mydiv").html(div.join(" ")); 

Ответ 6

Вот код, который даст вам желаемый результат. Преимущество этого кода в том, что он не проверяет каждый элемент, будь то тег или нет, проверяя, содержит ли он < или </, что, на мой взгляд, является хорошим, поскольку наш код не так сложно, как было бы, и нам не нужно проверять все значения, независимо от того, содержат они или нет < или </. (Меньший расчет, теоретически должен выполняться быстрее.)

var elements = $("#mydiv").contents(); //Get all contents of #mydiv
$("#mydiv").html(null); //Delete all elements from #mydiv

var count = 0; //This will be counting our elements

for(var i = 0; i < elements.length; i++){ //Go through all elements of #mydiv
    if(elements[i].nodeName == "#text"){ //If the element is a text block, then:

        var textElements = $(elements[i]).text().split(/\s+/g); //Split the text by all the spaces

        for(var j = 0; j < textElements.length; j++){ //Go through all elements inside the text block

            if(textElements[j] == "") continue; //The splitting of the text-block elements is not perfect, so we have to skip some elements manually

            count++; //Add to our count

            $("#mydiv").append(textElements[j] + " "); //Add this element to our cleared #mydiv

            if(count != 0 && count % 200 == 0){ //Every 200 elements, do this:
                $("#mydiv").append(" <span class='highlight'>highlight</span> "); //Add our highlight
            }
        }
    }else{ //If the element is not a text block, then:

        $("#mydiv").append(elements[i]); //Add the non-text element

        count++; //Add to our counter

        if(count != 0 && count % 200 == 0){ //Every 200 elements, do this:
            $("#mydiv").append(" <span class='highlight'>highlight</span> "); //Add our highlight

        }
    }
}

Ответ 7

При условии, что вы в порядке с использованием HTML #mydiv в качестве строки, одним из решений является использование string.replace с регулярным выражением и функцией замены, например:

function insertInHTMLEveryNWords(n, htmlString, insertString) {
  var wordCounter = 0,
      tagDepth = 0;
  return htmlString.replace(
    /<(\/?)([^>]+)>|[^<\s]+/g,
    function(match, forwardSlash, tagContent) {
      if (tagContent) { //matched a tag
        tagDepth += forwardSlash ? -1 : 1;
      } else { //matched a word
        wordCounter++;
      }
      if (!tagDepth && wordCounter >= n) {
        //if not inside tag and words are at least n,
        wordCounter = 0;
        return match + insertString;
      } else {
        return match;
      }
    });
}

Следующий фрагмент содержит рабочую демонстрацию подхода, упрощенную для вставки после каждых двух слов (если не в любом теге или непосредственно после следующего возможного закрывающего тега, как указано OP):

var htmlOriginal = document.getElementById('mydiv').innerHTML;

var htmlWithInsertions = insertInHTMLEveryNWords(
  2,
  htmlOriginal,
  '<div>[Inserted DIV after every 2 words or when not in any tag]</div>'
);

//inspect result in console
console.log(htmlWithInsertions);

//replace html in #mydiv
document.getElementById('mydiv').innerHTML = htmlWithInsertions;

function insertInHTMLEveryNWords(n, htmlString, insertString) {
  var wordCounter = 0,
      tagDepth = 0;
  return htmlString.replace(
    /<(\/?)([^>]+)>|[^<\s]+/g,
    function(match, forwardSlash, tagContent) {
      if (tagContent) { //matched a tag
        tagDepth += forwardSlash ? -1 : 1;
      } else { //matched a word
        wordCounter++;
      }
      if (!tagDepth && wordCounter >= n) {
        //if not inside tag and words are at least n,
        wordCounter = 0;
        return match + insertString;
      } else {
        return match;
      }
    });
}
<div id="mydiv">
  Some text, word3,
  <em>emphasized and <strong>strong</strong></em> text.
</div>

Ответ 8

Тег я является встроенным элементом, и невозможно вставить в него элемент блока, как div. И "highlight" не является допустимым атрибутом для div.

Чтобы достичь вставки, используйте span вместо div. И проверьте, какой атрибут необходим для ваших целей. Результат будет (с идентификатором как атрибутом):

<div id="mydiv">
   sample text sample text sample text...
   ......
   <i>inner<span id="highlight">highlight text</span> text </i> <i>sample text </i>
   ......
   <b>sample text </b> <i>sample text </i>
</div>

Ответ 9

Я предполагаю, что вы уже находите слово 200 и добавляете свой div после него, что-то вроде этого может быть?

varUntilSpace200 + '<div "highlight">highlight text</div>' + restOfInnerHTML;

Затем все, что вам нужно сделать, это проверить restOfInnerHTML, если после пробела 200 есть

"</"

если это так, просто добавьте все из этой позиции в первую

">"

var indof1 = restOfInnerHTML.indexOf("</");
var indof2 = restOfInnerHTML.indexOf("<");
var indof3 = restOfInnerHTML.indexOf(">");

if (indof1 < indof2) {
  varUntilSpace200 += restOfInnerHTML.substring(indof1,indof3);
  restOfInnerHTML = restOfInnerHTML.substring(indof3+1,restOfInnerHTML.length);
}