简体   繁体   中英

jQuery or Javascript: Find HTML text by character offset and length

I have some JSON: {"div_id":"pie1","str_offset":"5","str_length":"6"}

And I have the following HTML:

<div id="pie1">I like pie!</div>

I want to be able to wrap a <span> element around the matching text, ie, 6 text characters long starting 5 characters from the beginning of the text node. So in this example it would wrap "e pie!". Ideally, the solution would ignore the presence of any other tags, such as I like <b>pie!</b> and only count the text characters.

If a jQuery like selector is not feasible, it would be OK to just find the position of the str_offset, write the HTML, then find the end position and close the tag.

`

Starting with the simple example where we assume the div doesn't contain any child elements, you can do it something like this:

function wrapText(id, offset, length){
    $("#"+id).html(function(i,oldHtml) {
        return oldHtml.substr(0,offset) +
               "<span>" +
               oldHtml.substr(offset, length) +
               "</span>" +
               oldHtml.substr(offset + length);
    });
}
wrapText("pie1",5,6);   // obviously use values from your JSON here

Demo: http://jsfiddle.net/TfAAC/

When you call jQuery's .html() method with a callback function jQuery calls your function with the current html text and you return the new value.

The following more complicated code "works" if there are child elements within the div, but it potentially creates overlapping tags when it inserts the span tags:

function wrapText(id, offset, length){
    $("#"+id).html(function(i,oldHtml) {
        var i, c, spanStart, spanStop;
        for (i = 0, c = 0; i < oldHtml.length; i++) {
            if (c === offset)
               spanStart = i;
            else if (c === offset+length) {
               spanStop = i;
               break;
            }
            if (oldHtml.charAt(i) === "<"){
               while (++i < oldHtml.length && oldHtml.charAt(i) != ">" && oldHtml.charAt(i+1) != "<");
            }else
               c++;
        }        
        if (spanStart === undefined)
           return oldHtml;
        if (spanStop === undefined)
           spanStop = oldHtml.length;
        return oldHtml.slice(0, spanStart) +
               "<span>" + oldHtml.slice(spanStart, spanStop) + "</span>" +
               oldHtml.slice(spanStop);
    });
}

You can see in this demo: http://jsfiddle.net/TfAAC/1/ that the html produced by the above has span tags in the "right" places, but when the browser actually displays it it doesn't like it (at least, Firefox doesn't) because of the overlaps.

Have a look at this code: http://jsfiddle.net/5J93b/4/

Use wrapText(elem, 5, 6); to wrap six characters starting from position 5.

Use wrapText(elem, elem.textContent.length - 6, 6); to wrap the last six characters.

It will ignore HTML tags (side effect: no HTML tags will be present in the end).

Here is the code:

function wrapText(elem, start, length) {
    var before = elem.textContent.substr(0, start);
    var after = elem.textContent.substr(start + length, elem.textContent.length - length);
    var letters = elem.textContent.substr(start, length);
    elem.innerHTML = '';
    var text1=document.createTextNode(before);
    var text2=document.createElement('span');
    text2.style.backgroundColor='red';
    text2.innerHTML = letters;
    var text3=document.createTextNode(after);
    elem.appendChild(text1);
    elem.appendChild(text2);
    elem.appendChild(text3);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM