2

I have this issue with regex, it doesn't really have friendly syntax for me :(.

Basically I need to match some text and wrap the matched word/letter with a <strong>.

html = html.replace(new RegExp('(' + word + ')', 'ig'), function ($1, match) {
                                return '<strong>' + match + '</strong>';

Now everything works fine except that in some occasion, the previously added <strong> get matched to messing up the html.

So I basically need the html.replace function to ignore any <strong> word during the matching.

I have tried to change new RegExp('(' + word + ')' with new RegExp('(?!\<strong\>)(' + word + ')' but I still have issue.

Ex.

'<strong>Alpinestars</strong> SMX Plus Gore-Tex Boots'.replace(new RegExp('(o)(?!</strong>)', 'ig'), function ($1, match) {
                            return '<strong>' + match + '</strong>';});

returns

"<str<strong>o</strong>ng>Alpinestars</str<strong>o</strong>ng> SMX Plus G<strong>o</strong>re-Tex B<strong>o</strong><strong>o</strong>ts"
WonderLand
  • 5,494
  • 7
  • 57
  • 76

2 Answers2

2

You were close. You just had the order wrong. According to the following mdn page, the x(?!y) means: Matches x only if x is not followed by y.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp

So, this seems to work for me:

var word = 'and';
'dogs <strong>and</strong> cats <strong>and</strong>'.replace(
    new RegExp('(' + word + ')(?!</strong>)', 'ig'), 
    function ($1, match) {
        return '<strong>' + match + '</strong>';
    }
);
xdhmoore
  • 8,935
  • 11
  • 47
  • 90
2

You can check if you are not inside an element node with (?![^>]*>) look-ahead:

function escapeRegExp(string){
  return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}

var key = 'o';
var s = '<strong>Alpinestars</strong> SMX Plus Gore-Tex Boots';
var res = s.replace(RegExp(escapeRegExp(key) + '(?![^>]*>)', 'ig'), function (m) {
                            return '<strong>' + m + '</strong>';});
document.getElementById("t").innerHTML = res.replace(/>/g, "&gt;").replace(/</g, "&lt;");
<div id="t"/>

You also do not need any capturing groups (unless you are using alternations like boots|caps|hats) and do not have to use new with RegExp. I also added an escapeRegExp function from MDN to escape special characters in key if any.

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • I updated your answer with what worked for me. ( consider $key can be also a full word ... with your solution nothing was matched in that scenario ) – WonderLand Nov 18 '15 at 08:51
  • @Wonderland, your update was rejected, as it changes the answer completely. If you want to share your solution, please post it as a new answer. – trincot Nov 18 '15 at 08:56
  • 1
    @WonderLand: If you need to perform a case-insensitive search, yes, add the `i` modifier. I added it to the code. – Wiktor Stribiżew Nov 18 '15 at 08:58