-1

I have this javascript function I found, which replaces all occurences in a string. It works great, but I need it to only work for non-html elements, which simply means any part in the string that isn't between a "<" and ">".

String.prototype.replaceAll = function (strReplace, strWith) {
    // See http://stackoverflow.com/a/3561711/556609
    var esc = strReplace.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
    var reg = new RegExp(esc, 'ig');
    return this.replace(reg, strWith);
};

I want this as the "strReplace" string sometimes is found in html, hence messing up the HTML output. Any help is appreciated :)

PloxCake
  • 73
  • 1
  • 5
  • A question: `Test` will be treated as one word (`=test`) or not? – Sphinx Jul 23 '18 at 21:12
  • 1
    matching html with reg exp is a bad idea.... – epascarello Jul 23 '18 at 21:13
  • @Sphinx Optimally I'd want it treated as the word "test" yes, but if that makes things more complicated than I'd be more than happy just to receive a solution with it being treated some other way – PloxCake Jul 23 '18 at 21:15
  • @epascarello so I've heard but I don't know how to perform this task otherwise – PloxCake Jul 23 '18 at 21:15
  • If so, you can get all text nodes of one dom element first, then uses one loop to `replaceAll` for each text nodes. If you don't care about keeping original html tag, you can convert element to plain text by `element.innerText`, then apply `replaceAll` – Sphinx Jul 23 '18 at 21:17
  • @sphinx I'm not quite sure what you mean nor how to execute it, especially not with the complex regex I require posted in the OP. Could you possibly provide me a demo? – PloxCake Jul 23 '18 at 21:19
  • It is rather complex thing to do, basically you need to map all of the html to tag and position. You than find the place, and than alter all of the tags length, positions, and rebuild the html string. – epascarello Jul 23 '18 at 21:27

1 Answers1

0

Assuing you'd like to replace one string with replaceAll method:

  1. if one string is not one valid html, then treat it as plain text.

  2. if one string is one valid html, then loop each textContent to apply replaceAll.

The solution (uses element.innerHTML instead of regex expression, as @epascarello said, it is not a good idea for using regex to match html):

  1. load the target string into one dom element with .innerHTML

  2. loop this element to get all text node.

  3. apply replaceAll for the content of the text nodes.

  4. return el.innerHTML

String.prototype.replaceAll = function (strReplace, strWith) {
    // See http://stackoverflow.com/a/3561711/556609
    var esc = strReplace.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
    var reg = new RegExp(esc, 'ig');
    return this.replace(reg, strWith);
}

function replaceAll2 (targetString, keyword, replaceWord) {
  if (!keyword) return targetString
  let el = document.createElement('div')
  el.style.display='none'
  el.innerHTML = targetString
  let walk = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, null, false)
  let next = walk.nextNode()
  while (next) {
    next.textContent = next.textContent.replaceAll(keyword, replaceWord)
    next = walk.nextNode()
  }
  return el.innerHTML
}

let test1 = 'I am a plain text'
let test2 = 'I <span>am</span> a <p>plain</p> text'
console.log(replaceAll2(test1, 'pl', '1'))
console.log(replaceAll2(test2, 'pl', '2'))
Sphinx
  • 10,519
  • 2
  • 27
  • 45
  • Thank you, that's exactly what I looked for! I do however have a small issue now when replacing the targeted word with html-content, I'm assuming due to the "next.textContent" row. – PloxCake Jul 23 '18 at 22:19
  • if replace keyword with `html-content`, the tag will be escaped. Probably this is the issue you mentioned. if `html-content`, you may have to parse `replaceWord` to dom element, then uses `Element.insertBefore` instead of `String.replace`. – Sphinx Jul 23 '18 at 22:36
  • I guess, I managed to surpass the problem by applying the html afterwards, using the first replace function. Thanks once again, I really appreciate it! – PloxCake Jul 23 '18 at 22:41