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"
10
  • ok just tried, unfortunately it is not working as expected. still the <strong> is matched if the word value is O for ex. ( while o is not matching it ) Commented Nov 18, 2015 at 7:41
  • 1
    I think you just need RegExp( word + '(?![^<]*</strong>)'). You do not have to escape a / inside a regexp constructor. Commented Nov 18, 2015 at 7:43
  • @stribizhev looks better but still the closing tag is matched </strong> Commented Nov 18, 2015 at 7:46
  • Please post the input string and other pertinent code to repro. Commented Nov 18, 2015 at 7:53
  • I added an example using the @xdhmoore suggestion Commented Nov 18, 2015 at 7:59

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

3 Comments

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, your update was rejected, as it changes the answer completely. If you want to share your solution, please post it as a new answer.
@WonderLand: If you need to perform a case-insensitive search, yes, add the i modifier. I added it to the code.
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>';
    }
);

1 Comment

check my update on the question ( there are still some issues )

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.