Life would be simpler with lookbehind assertions.
/((`)[\s\S]*?)?\*\*([\s\S]+?)\*\*([\s\S]*?\2)/gm
((`)[\s\S]*?)? #capture any characters (or none) preceded by a backtick (captured for a later use in the RE). Optionnal - non-greedy.
\*\*([\s\S]+?)\*\* #capture any characters surrounded by asterisks.
([\s\S]*?\2) #capture any characters (including empty string) followed by the capture #2 (empty or backtick).
If the first group is empty, the last one will match an empty string.
Then we filter our result.
var str = "Lorem `ipsum **dolor** sit` amet, **consectetur** adipisicing elit dolor `**sit amet**` adi";
str = str.replace(/((`)[\s\S]*?)?\*\*([\s\S]+?)\*\*([\s\S]*?\2)/gm, function(m, p1, p2, p3, p4){
return p1 && p4 ? m : "<b>" + p3 + "</b>";
});
return p1 && p4 ? m : "<b>" + p3 + "</b>";
If p1
and p4
are not empty/undefined, that means our matched string starts and ends with backticks. We return it without changes.
This example outputs :
Lorem `ipsum **dolor** sit` amet, consectetur adipisicing elit dolor `**sit amet**` adi
It's a bit tricky, imo. But as you point out, it's just for the sake of interest. ;)