How can I remove all HTML elements from a string excluding a special class?

Viewed 575

I've a problem. I'm currently looking for a way to remove any HTML elements from a string. But there are two conditions:

  1. The content of the elements should be kept
  2. Special elements with a defined class should not be removed

I've already tried lots of things and looked at plenty of questions/answers on SO, but unfortunately I can't really figure out any of the answers. Unfortunately, this exceeds my abilities by far. But I would like to know how something like this works.

Question/Answers I've tried: How to strip HTML tags from string in JavaScript?, Strip HTML from Text JavaScript

So when I have for example a string like this:

You have to pay <div class="keep-this">$200</div> per <span class="date">month</span> for your <span class="vehicle">car</span>

It should looks like this after stripping:

You have to pay <div class="keep-this">$200</div> per month for your car

I've actually tried following things:

jQuery(document).ready(function ($) {
 let string = 'You have to pay <div class="keep-this">$200</div> per <span class="date">month</span> for your <span class="vehicle">car</span>';

 console.log(string);

 function removeHTMLfromString(string) {
  let tmp = document.createElement("DIV");

  tmp.innerHTML = string;
  return tmp.textContent || tmp.innerText || "";
 }

 console.log(removeHTMLfromString(string));

 console.log(string.replace(/<[^>]*>?/gm, ''));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

And I've also tried out a regex tool to see what get's removed, but unfortunately, I'm not making much progress here either:

https://www.regexr.com/50qar

I would love if someone can help me with this task. Thanks a lot!

Update

Maybe there is a way doing it with just a regex? If yes, how can I exclude my elements with a special class when using this regex: /<\/?[^>]+(>|$)/g?

2 Answers

It may be a little big code. But I think it may help you.

let str = 'You have to pay <div class="keep-this">$200</div> per <span class="date">month</span> for your <span class="vehicle">car</span> <div class="keep-this">$500</div> also';

const el = document.createElement("div");
el.innerHTML = str;

// Get all the elements to keep
const keep = el.querySelectorAll(".keep-this");

// Replace the keeping element from the original string
// With special pattern and index so that we can replace
// the pattern with original keeping element
keep.forEach((v, i) => {
  const keepStr = v.outerHTML;
  str = str.replace(keepStr, `_k${i}_`);
});

// Replace created element's innerHTML by patternised string.
el.innerHTML = str;

// Get the text only
let stringify = el.innerText;

// Replace patterns from the text string by keeping element
keep.forEach((v,i) => {
  const keepStr = v.outerHTML;
  stringify = stringify.replace(`_k${i}_`, keepStr);
});

console.log(stringify);

Leave me comment if anything misleading.

Update: Regular Expression approach

The same task can be done by using a regular expression. The approach is-

  1. Find all the keepable elements by regex and store them.
  2. Replace all the keepable elements from the input string by an identical pattern
  3. Remove all the HTML tags from the sting.
  4. Replace the identical patterns by keepable elements.

let htmlString = 'You have to pay <div class="keep-this">$200</div> per <span class="date">month</span> for your <span class="vehicle">car</span> Another <div class="keep-this">$400</div> here';

// RegExp for keep elements
const keepRegex = /<([a-z1-6]+)\s+(class=[\'\"](keep-this\s*.*?)[\'\"])[^>]*>.*?<\/\1>/ig;

// RegExp for opening tag
const openRegex = /<([a-z1-6]+)\b[^>]*>/ig;

// RegExp for closing tag
const closeRegex = /<\/[a-z1-6]+>/ig;

// Find all the matches for the keeping elements
const matches = [...htmlString.matchAll(keepRegex)];

// Replace the input string with any pattern so that it could be replaced later
matches.forEach((match, i) => {
  htmlString = htmlString.replace(match[0], `_k${i}_`);
});

// Remove opening tags from the input string
htmlString = htmlString.replace(openRegex, '');

// Remove closing tags from the input string
htmlString = htmlString.replace(closeRegex, '');

// Replace the previously created pattern by keeping element
matches.forEach((match, index) => {
  htmlString = htmlString.replace(`_k${index}_`, match[0]);
})

console.log(htmlString);

If date and vehicles div and class are coming from another function, you should just get rid of it from there.

Related