4

I have some text:

<p>hello world. This is a test paragraph.</p>

I want to add an <em> tag at start positions and </em> at end positions giving us:

<p>
  <em>hello</em> world. This is a <em>test</em> paragraph.
</p>

I have a list of start and end positions

<lst name="offsets">
  <int name="start">0</int>
  <int name="end">5</int>
  <int name="start">22</int>
  <int name="end">27</int>
</lst>

Is there an easy way of doing this?

Here is how I did it (slight modification of the answer):

var p = doc+=" "//document.querySelector("#content"),//I added a space to the end of the document because if we try to wrap the em tags around the word we are looking for and it is at the end of the document then it gives us undefined.
    textArray = p.split('');
    //offsets = [{ start: 0, end: 5 }, { start: 22, end: 27 }];

    offsets.forEach(function (offset) {    
    textArray[offset.start] = '<em>' + textArray[offset.start];
    textArray[offset.end] = '</em>' + textArray[offset.end];
});

document.querySelector("#content").innerHTML += textArray.join('');
document.querySelector("#content").innerHTML += "<hr>";
3
  • So you want to add a <em> tag at column indicated inside element with name "start" of every <p> element? In this case, column 2289? Commented Nov 23, 2015 at 19:41
  • Ah sorry, I meant to change the position, will do now Commented Nov 23, 2015 at 19:46
  • Also I can simply get the element <p> and get its text. From there I want to edit the text and add the <em> tags Commented Nov 23, 2015 at 19:52

3 Answers 3

6

Here is a simple example that doesn't require jQuery.

Example Here

Start with an offset array of objects to determine the start/end values.

[
  { start: 0, end: 5 },
  { start: 22, end: 27 }
]

Then iterate over the offset array:

var p = document.querySelector('p'),
    textArray = p.innerText.split(''),
    offsets = [{ start: 0, end: 5 }, { start: 22, end: 27 }];

offsets.forEach(function (offset) {    
    textArray[offset.start] = '<em>' + textArray[offset.start];
    textArray[offset.end] = '</em>' + textArray[offset.end];
});

p.innerHTML = textArray.join('');
<p>hello world. This is a test paragraph.</p>


If you would like to parse the list elements in order to create the offset array:

Example Here

var p = document.querySelector('p'),
    textArray = p.innerText.split(''),
    offsets = [];

Array.prototype.forEach.call(document.querySelectorAll('lst > int[name="start"]'), function (el) {
    offsets.push({start: el.innerText, end: el.nextElementSibling.innerText});
});

offsets.forEach(function (offset) {    
    textArray[offset.start] = '<em>' + textArray[offset.start];
    textArray[offset.end] = '</em>' + textArray[offset.end];
});

p.innerHTML = textArray.join('');
<p>hello world. This is a test paragraph.</p>

<lst name="offsets">
  <int name="start">0</int>
  <int name="end">5</int>
  <int name="start">22</int>
  <int name="end">27</int>
</lst>

Sign up to request clarification or add additional context in comments.

2 Comments

This actually has a problem when the text we are wrapping with <em> is at the end, I get an undefined because the character array is of a length and it tries to add the </em> + textArray[offset.end] thus being nothing and giving us the undefined. I solved it (rather dirty fix) by adding a space to the end of the document. I have added my code as an edit to the original question.
Nice solution. Testing if (textArray[offset.end] ? textArray[offset.end] : '') will sort the Undefined problem.
1

Would it be better to list the particular words you want to change?

var arr = ["hello", "test"];
$('p').html(function(i,html) {
    return html.split(/\s+/).map(function(u,j) {
        return arr.indexOf(u) > -1 ? '<em>' + u + '</em>' : u;
    })
    .join(' ');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<p>
hello world. This is a test paragraph.
</p>

Comments

1

You can loop over the <lst> you've provided like this:

//as we insert tags, the length of our string will change.  we need a counter and an offset to track that
var counter = 0;

//loop over each start tag in the list
$('lst[name="offsets"] int[name="start"]').each(function() {

    //get the start tag
    var startValue = $(this);
    //get the next tag, the end tag
    var endValue = startValue.next();
    //convert the start tag's text to an int
    var startInt = parseInt(startValue.text());
    //convert the end tag's text to an int
    var endInt = parseInt(endValue.text());

    //load the paragraph's html
    var str = $('p').html();

    //offset length of inserted string, e.g. "<em></em>" means 9 characters are insearted each time this loop runs
    var offsetOpen = (counter * 9); 
    //offset the closing tag by the length of the start tag
    var offsetClose = offsetOpen + 4; 

    //insert the start tag at the right position
    $('p').html([str.slice(0,startInt + offsetOpen), "<em>", str.slice(startInt + offsetOpen)].join(''));

    str = $('p').html();

    //insert the closing tag at the right position
    $('p').html([str.slice(0,endInt + offsetClose), "</em>", str.slice(endInt + offsetClose)].join(''));

    //increment the counter
    counter++;

});

You can see it working at this JS Fiddle:

https://jsfiddle.net/jqzrovoh/3/

Hope that helps!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.