Help write a regex that will surround certain text with <strong> tags only if the <strong> tag is missing
I have several posts on the website; all these messages are chat chains of this type:
AD: Hey,
BC: What? AD: Nothing found BC: Good
They are marked as simple paragraphs surrounded by tags <p>
.
Using the javascript replace function, I want all instances of "AD" at the start of the conversation (ie all instances of "AD" at the beginning of the line followed by ":") to be surrounded <strong>
, but only if the instance is not already tagged <strong>
.
What regex should I use to accomplish this? Am I trying to do what it recommends?
The code I'm using looks like this:
var posts = document.getElementsByClassName('entry-content');
for (var i = 0; i < posts.length; i++) {
posts[i].innerHTML = posts[i].innerHTML.replace(/some regex here/,
'replaced content here');
}
a source to share
If AD:
always found at the beginning of a line, then the following regex should work using a switch m
:
.replace(/^AD:/gm, "<strong>AD:</strong>");
You don't need to check for existence <strong>
, because it ^
will match the beginning of the line, and the regex will only match if the sequence of characters following the beginning of the line is AD:
.
You are not going against the "Don't use regex to parse HTML" recommendation because you are not parsing HTML, you are simply replacing the string with another string.
An alternative to regular expression would work with ranges by creating a range that selects the text and then using execCommand to make the text bold. However, I think it will be much more complicated and you are likely to run into differences in browser implementation. A regular path should be sufficient.
After seeing the comment, the following regex will work fine:
.replace(/<(p|br)>AD:/gm, "<$1><strong>AD:</strong>");
a source to share
Wouldn't it be easier to set the class or style property of the found paragraph to text-weight: bold or a class that does roughly the same thing? This way, you don't have to worry about adding tags or finding existing tags. May also work better if you don't need to do string replacement.
If you really want to add strong tags, I would suggest using the DOM functions to find your paragraph's childNodes that are <strong>, and if you don't find it, add it and move the original (text) childNode of the paragraph into it.
a source to share
Using regular expressions is innerHTML
not reliable and can potentially lead to problems. The correct way to do this is through a tedious process, but much more reliable.
eg.
for (var i = 0, l = posts.length; i < l; i++) {
findAndReplaceInDOM(posts[i], /^AD:/g, function(match, node){
// Make sure current node does note have a <strong> as a parent
if (node.parentNode.nodeName.toLowerCase() === 'strong') {
return false;
}
// Create and return new <strong>
var s = document.createElement('strong');
s.appendChild(document.createTextNode(match[0]));
return s;
});
}
And the function findAndReplaceInDOM
:
function findAndReplaceInDOM(node, regex, replaceFn) {
// Note: regex MUST have global flag
if (!regex || !regex.global || typeof replaceFn !== 'function') {
return;
}
var start, end, match, parent, leftNode,
rightNode, replacementNode, text,
d = document;
// Loop through all childNodes of "node"
if (node = node && node.firstChild) do {
if (node.nodeType === 1) {
// Regular element, recurse:
findAndReplaceInDOM(node, regex, replaceFn);
} else if (node.nodeType === 3) {
// Text node, introspect
parent = node.parentNode;
text = node.data;
regex.lastIndex = 0;
while (match = regex.exec(text)) {
replacementNode = replaceFn(match, node);
if (!replacementNode) {
continue;
}
end = regex.lastIndex;
start = end - match[0].length;
// Effectively split node up into three parts:
// leftSideOfReplacement + REPLACEMENT + rightSideOfReplacement
leftNode = d.createTextNode( text.substring(0, start) );
rightNode = d.createTextNode( text.substring(end) );
parent.insertBefore(leftNode, node);
parent.insertBefore(replacementNode, node);
parent.insertBefore(rightNode, node);
// Remove original node from document
parent.removeChild(node);
}
}
} while (node = node.nextSibling);
}
a source to share