1

I am trying to replace the font color of "bad" throughout an HTML page to red but there are two main issues, firstly it repeats the entire sentence before replacement and I do not want that and also the bad in "badly" was also replaced but I just want only the font in the word "bad" replaced. How do I go about this? Here is my code

 window.onload = function() {
   var text = document.getElementById("content");
   var str = text.innerHTML,
     reg = /red/ig;

   var toStr = String(reg);
   var color = (toStr.replace('\/g', '|')).substring(1);

   var colors = color.replace("|");

   if (colors.indexOf("red") > -1) {
     str = str.replace(/bad/g, '<span style="color:red;">bad</span>');
   }


   document.getElementById("updated").innerHTML = str;
 }
<div id="content">are they good or bad, tell me how badly it is if bad.</div>
<div id="updated"></div>
j08691
  • 204,283
  • 31
  • 260
  • 272
  • use `\b` or whatever it is to put "word boundaries" around "red". that'd prevent `redemption` from getting mangled. – Marc B Jun 13 '16 at 19:46
  • You might want to break up the contents of the div into an array of words, then process each word individually. You should be able to do this like: var ih = document.getElementById('content').innerHTML;var words = ih.split(/\b/g);for(var i=0;i – raphael75 Jun 13 '16 at 20:00
  • \b helped with the boundary on "bad" but I still haven't found solution to the repetition. @MarcB – Scott Mckay Jun 13 '16 at 20:14
  • "_firstly it repeats the entire sentence before replacement and I do not want that_"... what does that even mean? – Patrick Roberts Jun 13 '16 at 20:20

2 Answers2

1

use \b (a word boundary token) as said by raphael75
str = str.replace(/\b(bad)\b/gi, '<span style="color:red;">$1</span>');
also, I:

  • added the i modifier, for it to be case insensitive (capture Bad, BAD, bad)
  • encapsulated (bad) in the regEx to call again with $1, this keeps the case (if capitalized Bad, stays Bad)
    var str = "bad incredibad badly Bad, testing bad, bad. bad";
    str = str.replace(/\b(bad)\b/gi, '<span style="color:red;">$1</span>');
    document.getElementsByTagName('p')[0].innerHTML = str;
    <p></p>

regex101 is a go-to place for JavaScript RegEx

Community
  • 1
  • 1
warkentien2
  • 969
  • 13
  • 20
0

To replace text in HTML documents, it is a good idea to traverse the DOM tree and replace the content of text nodes where needed.

To match complete words only ("bad" but not "badly"), use regex with word boundary anchors \b.

The following implementation performs depth-first DOM tree traversal and replaces text nodes containing the word "bad" with text nodes for both the text before and after that word as well as a <span style="color: red">bad</span> in place of "bad":

var walk = (node, func) => {
  var children = node.childNodes;
  for (var i = children.length - 1; i >= 0; --i) {
    walk(children[i], func);
  }
  func(node);
};

var highlight = (text, color) => {
  var span = document.createElement("span");
  span.style.color = color;
  span.appendChild(document.createTextNode(text));
  return span;
};

var root = document.getElementById("content");

walk(root, (node) => {
  if (node.nodeType != Node.TEXT_NODE) return;
  var texts = node.data.split(/\bbad\b/),
      length = texts.length;
  if (length > 1) {
    var fragment = texts.reduce((fragment, text, i) => {
      fragment.appendChild(document.createTextNode(text));
      if (i < length - 1) fragment.appendChild(highlight("bad", "red"));
      return fragment;
    }, document.createDocumentFragment());
    node.parentNode.replaceChild(fragment, node);            
  }
});
<div id="content">are they good or bad, tell me how badly it is <bad>bad bad bad</bad> if bad.</div>

See also: JavaScript: Add elements in textNode

Community
  • 1
  • 1
le_m
  • 19,302
  • 9
  • 64
  • 74