Zuse
Zuse

Reputation: 103

Search HTML and phrase after every instance of certain word

The title pretty much explains it. I want to add a user defined word or phrase (for example: 'greatest') after every appearance of a specific word (for example: 'the') in JavaScript. So every time 'the' appears in the text of the HTML (blah blah blah the blah blah) the JavaScript will inject 'greatest' (blah blah blah the greatest blah blah). I was trying to figure this out using regular expressions but have come up short of adding it directly into the HTML.

Upvotes: 1

Views: 314

Answers (4)

Redu
Redu

Reputation: 26161

To do this job dynamically, one way is inventing our own String.prototype.affix() method. This new method will do what you want and if the last argument is true it affixes the provided string to affix (second argument) to the end and if false to the front of the searched piece of sub-string (first argument). I've assigned true as a default value to the last parameter.

String.prototype.affix = function(s,a,b = true){
  var r = new RegExp(s,"g");
  return b ? this.replace(r,"$&" + " " + a)
           : this.replace(r,a + " " + "$&");
}

console.log("this is the book and the author is him".affix("the", "greatest",true));

Upvotes: 0

gaetanoM
gaetanoM

Reputation: 42054

My proposal is to use TreeWalker to search for all text nodes in the body:

function replaceTextInPage(el, txtMatch, txtToReplace) {
  txtToReplace = (txtToReplace.length > 0) ? ' ' + txtToReplace : '';
  var walk = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, null, false);
  while (n = walk.nextNode()) {
    if (n.textContent.trim().length > 0) {
      n.textContent = n.textContent.replace(new RegExp(txtMatch, "gi"), txtMatch + txtToReplace);
    }
  }
}

window.onload = function () {
  document.getElementById('btn').addEventListener('click', function() {
    replaceTextInPage(document.body, document.getElementById('txtToFind').value, document.getElementById('txtToAdd').value)
  }, false);
}
<button id="btn">Replace string</button><br/>
Text to search: <input id="txtToFind" type="text" value="the"><br/>
Text to add at the end: <input id="txtToAdd" type="text" value="greatest"><br/>
<div style="width: 100%;height: 100px;">It seems to only remove <span style="color: red;">the</span> first occurrence of abc in <span style="color: red;">the</span> string above. How can I replace all occurrences of it?</div>

Upvotes: 1

blex
blex

Reputation: 25634

Indeed, Regex is perfect to do that. You can use the String.replace() function to replace the text:

someString.replace(/\b(the)\b/ig, "$1 greatest");

Here, \b represent word boundaries (spaces, periods, etc.) and will avoid replacing "other" with "othe greatest r", the parenthesis around "the" allow you to select it (to use it in the replacement, by using $1). Then, i and g are flags to make your regex case-Insensitive and Global (look for multiple occurrences).

But that's not where most of the work needs to be done. Replacing the text of an element might interfere with the actual HTML. To avoid that, you can apply a function recursively to only target text nodes:

document.getElementById('btn').addEventListener('click', function() {
  doReplace(/\b(the)\b/ig, "$1 greatest", document.body);
  this.style.visibility = 'hidden';
});

function doReplace(search, replacement, element) {
  if (element.nodeType == 3) { // if the element is a text node, replace the content
    element.nodeValue = element.nodeValue.replace(search, replacement);
  } else { // otherwise, apply this function to all children
    var children = element.childNodes;
    for (var i = 0; i < children.length; i++) {
      doReplace(search, replacement, children[i]);
    }
  }
}
<button id="btn">Add "greatest"!</button>
<h1>The pie was cold</h1>
<p>I was at the restaurant the other day, and the waiter took my order. The problem? My pie was cold!</p>

Upvotes: 0

Daniel Moses
Daniel Moses

Reputation: 5858

Here is some code that will do what you want. Notice that it doesn't change "The orange" since it's case sensative. Notice also that it doesn't change the alerted "the orange" because that exists in a script element.

function getTextNodesThatContain(text) {
    var textNodes = $(document).find(":not(iframe, script, style)")
      .contents().filter( 
          function() {
           return this.nodeType == 3 
             && this.textContent.indexOf(text) > -1;
    });
    return textNodes;
};

$(document).ready(function() {
getTextNodesThatContain("the").each(function(ind, item) { 
  item.nodeValue = item.nodeValue.replace("the", "the greatest");
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

This is the apple.
<div> this is the orange. </div>
<script>
  function alertme() {
  alert("the orange");
    }
  </script>
<a href="javascript:alertme()">The orange</a>

Upvotes: 1

Related Questions