Reputation: 632
I have an Html String like <font>New</font><font face="Akronim---Regular" color="#00ff00">Text</font>
, With the use of JavaScript Regex i wanted to remove font tags with no attributes.
So the output of the above html string should be New<font face="Akronim---Regular" color="#00ff00">Text</font>
Below is the code, which helps me to strip all the font tags, But i am only require to strip font tags with no attribute.
var replace = new RegExp('<'+'font'+'[^><]*>|<.'+'font'+'[^><]*>','g')
var text = '<font>New</font><font face="Akronim---Regular" color="#00ff00">Text</font>';
console.log(text.replace(replace, ''))
Thanks in advance.
Upvotes: 2
Views: 270
Reputation: 31692
If you want to do it with a regex, you'll have to go tag by tag while keeping track of nesting levels so that you know when to remove a closing tag and when not.
To do so simply use an array that you constantly push
/pop
to/from it the type of the tag you encounter. When you encounter an opening tag, you push
true
if it has attributes and false
if it doesn't, you then remove it if it doesn't have attributes. When you encounter a closing tag, you pop
the type of the last encountered opening tag, if it had attributes (true
), you skip to the next one, if it didn't have them (false
) you remove it.
The regex should go over the opening and the closing tags in one run while giving us info about whether its a closing or an opening one and whether it has attributes or not. To do so we use regex like so <\/?font [^\s]*?>
, we group (\/)
and ([^\s]*?)
because whether or not those groups get matched, we will know if it is a closing tag or not and if it has attributes or not respectively (for example, if we match the /
then it's a closing tag). We add in the \s*
to handle empty spaces and the resulting regex is /<(\/)?\s*font\s*([^\s]*?)\s*>/g
.
Here is the function that does the job:
function stripEmptyFonts(htmlString) {
var tagTypes = [];
return htmlString.replace(/<(\/)?\s*font\s*([^\s]*?)\s*>/g, function(match, closingSlash, attributes) {
if(!closingSlash) { // if it is an opening tag (no '/' was matched)
tagTypes.push(!!attributes); // push true to the array tagTypes if it has attributes, otherwise push false (attributes will either be a string or null, we use the double negation !! to convert it to a boolean)
return attributes ? match : ""; // remove it if it has no attributes, otherwise keep it as is (read the docs of String#replace method)
} else { // if it is a closing tag (a '/' was matched)
return tagTypes.pop() ? match : ""; // if the last tag we encounterd had attributes (pop returned true) we skip this closing tag, otherwise (pop return false) we remove it
}
});
}
Example:
function stripEmptyFonts(htmlString) {
var tagTypes = [];
return htmlString.replace(/<(\/)?\s*font\s*([^\s]*?)\s*>/g, function(match, closingSlash, attributes) {
if(!closingSlash) {
tagTypes.push(!!attributes);
return attributes ? match : "";
} else {
return tagTypes.pop() ? match : "";
}
});
}
var html = `
<font>New</font>
<font color="red">Hello <font>world</font>!</font>
<font>Hello <font color="blue">back</font>!</font>
<font>ABCD<font>EFGH<font color="black">IJKL<font>MNOP<font color="red">QRST</font>UVWX</font>YZ</font>1234</font>5678</font>`
console.log(stripEmptyFonts(html));
Upvotes: 2
Reputation: 1676
if you have no access of DOM element then you can try this answer
<script>
let htmlString = '<font>Hello </font><font>New <font face="Akronim-Regular">world</font></font>';
let expoString = htmlString.split('<font>');
expoString = expoString.filter(function(el) {
return el != null && el != "";
});
for (let i = 0; i < expoString.length; i++) {
let startTag = expoString[i].split('<font').length - 1;
let endTag = expoString[i].split('</font>').length - 1;
for (let j = 1; j <= endTag - startTag; j++) {
expoString[i] = expoString[i].replace('</font>', '');
}
}
console.log(expoString.join('')); // here you can return string instead
Upvotes: 0
Reputation: 177885
Have a look at this. Do not use RegEx to manipulate HTML
The container could be created in memory if needed
On Node you can use https://www.npmjs.com/package/jsdom
document.querySelectorAll("font").forEach(f => {
const parent = f.parentNode;
if (f.attributes.length === 0) {
if (f.innerHTML === "") { // remove empty fonts - we could do this before too
parent.removeChild(f);
} else {
f.childNodes.forEach(child => parent.insertBefore(child.cloneNode(true), f));
parent.removeChild(f);
}
}
});
console.log(document.getElementById("container").innerHTML)
<div id="container">
<font>Hello
<font face="Akronim---Regular">world</font>
</font>
<font></font>
<font>New</font>
<font face="Akronim---Regular" color="#00ff00">Text</font>
</div>
Upvotes: 2