1

I have a function that wraps text with a span

$(".ui-content").html(function (i, v) 
  {  
     return v.replace(/(CANADA)/gi, '<span class="query">$1</span>'); 
});

However when I pass in the term "div" or "span" or "a" which are html, the page gets messed up badly of course.

What can I change the regex to remove only text that is not part of a html code like <strong> but does work on A strong person is a helpful friend

Ian Vink
  • 66,960
  • 104
  • 341
  • 555

3 Answers3

1

Node manipulations to the rescue, as always!

function toArray(obj) {
    var r = [];

    for(var i = 0; i < obj.length; i++) {
        r.push(obj[i]);
    }

    return r;
}

$('.ui-content').each(function() {
    var stack = [this];
    var c, n;

    while(c = stack.pop()) {
        var childNodes = toArray(c.childNodes);

        for(var i = 0; n = childNodes[i]; i++) {
            if(n.nodeType === 1) {
                stack.push(n);
            } else if(n.nodeType === 3) {
                var matches = n.nodeValue.split(/(CANADA)/i);

                for(var i = 0; i < matches.length; i++) {
                    var newNode;

                    if(/CANADA/i.test(matches[i])) {
                        newNode = document.createElement('span');
                        newNode.className = 'query';
                        newNode.appendChild(document.createTextNode(matches[i]));
                    } else {
                        newNode = document.createTextNode(matches[i]);
                    }

                    n.parentNode.insertBefore(newNode, n);
                }

                n.parentNode.removeChild(n);
            }
        }
    }
});

Here's a demo jsFiddle.

Ry-
  • 218,210
  • 55
  • 464
  • 476
  • ++1 just because I will use it for awesomely different purpose `:)` cheers – Tats_innit Jul 05 '12 at 02:38
  • @Tats_innit: Wait a minute... it doesn't entirely work... maybe. (I *had* a typo, but jsFiddle isn't responding now.) – Ry- Jul 05 '12 at 02:38
  • Neah I needed a Node manipulation code start I am using this sample what a coincidence! + 1 `:)` I will make it work man all good keep my +1 ; anyhoo favouriting OP's question – Tats_innit Jul 05 '12 at 02:39
  • I wont be using it for regex purpose, thanks anyways bruv! thnx `:)` – Tats_innit Jul 05 '12 at 02:47
1

Same concept, as @elclanrs, but with an imitation of negative look behind:

$(".ui-content").html(function (i, v) {       
     return v.replace(/([^</])(strong)/gi, ' <span class="query">$2</span> ');
});​

http://jsfiddle.net/39VMe/

Also a good article about how to treat certain limitations of JavaScript regexp: http://blog.stevenlevithan.com/archives/mimic-lookbehind-javascript

Alex Pakka
  • 9,466
  • 3
  • 45
  • 69
0

I know people usually insist in not using regex for parsing html but hey this seems to work just fine. This uses a negative lookahead to replace only the word "strong" and not actual <strong> tags:

/strong(?!>)/

Edit:

Use this regex which is more flexible and allows for attributes:

/strong(?!(>|\s\w+=))/g;

In any case, it all depends on your HTML. If regex don't do it then you'll have to parse properly.

Demo: http://jsfiddle.net/mGLjb/2/

elclanrs
  • 92,861
  • 21
  • 134
  • 171
  • This regexp will not work if the **strong** tag has any attributes. In typical HTML negative look behind would work better. But it is not supported in JS. – Alex Pakka Jul 05 '12 at 03:09
  • Oh I see, didn't really test other options but I updated the regex and example it should work fine now – elclanrs Jul 05 '12 at 03:32