admin管理员组

文章数量:1405311

I have a string (partly HTML) where I want to replace the string :-) into bbcode :wink:. But this replacement should not happen within <pre>, but in any other tag (or even not within a tag).

For example, I want to replace

:-)<pre>:-)</pre><blockquote>:-)</blockquote>

to:

:wink:<pre>:-)</pre><blockquote>:wink:</blockquote>

I already tried it with the following RegEx, but it does not work (nothing gets replaced):

var s = ':-)<pre>:-)</pre><blockquote>:-)</blockquote>';
var regex = /:\-\)(?!(^<pre>).*<\/pre>)/g;
var r = s.replace(regex, ':wink:');

Can someone please help me? :-)

I have a string (partly HTML) where I want to replace the string :-) into bbcode :wink:. But this replacement should not happen within <pre>, but in any other tag (or even not within a tag).

For example, I want to replace

:-)<pre>:-)</pre><blockquote>:-)</blockquote>

to:

:wink:<pre>:-)</pre><blockquote>:wink:</blockquote>

I already tried it with the following RegEx, but it does not work (nothing gets replaced):

var s = ':-)<pre>:-)</pre><blockquote>:-)</blockquote>';
var regex = /:\-\)(?!(^<pre>).*<\/pre>)/g;
var r = s.replace(regex, ':wink:');

Can someone please help me? :-)

Share Improve this question edited Nov 3, 2009 at 12:10 Peter Boughton 112k32 gold badges123 silver badges177 bronze badges asked Nov 3, 2009 at 11:40 acmeacme 14.9k8 gold badges76 silver badges114 bronze badges 1
  • Don't try to parse HTML nodes with regex; HTML is not Regular. Use a proper HTML parser that produces a DOM - for JavaScript, jQuery is an ideal choice. – Peter Boughton Commented Nov 3, 2009 at 12:12
Add a ment  | 

5 Answers 5

Reset to default 3

This ought to do it:-

var src = ":-)<pre>:-)</pre><blockquote>:-)</blockquote>"

var result = src.replace(/(<pre>(?:[^<](?!\/pre))*<\/pre>)|(\:\-\))/gi, fnCallback)

function fnCallback(s)
{
    if (s == ":-)") return ":wink:"
    return s;
}

alert(result);

It works because any pre element will get picked up by the first option in the regex and once consumed means that any contained :-) can't be matched since the processor will have moved beyond it.

You could avoid hellish regexes altogether if you use a suitable library such as jQuery, e.g.:

var excludeThese = ['pre'];

// loop over all elements on page, replacing :-) with :wink: for anything
// that is *not* a tag name in the excludeThese array

$('* not:(' + excludeThese.join(',') + ')').each(function() {
    $(this).html($(this).html().replace(/:\-\)/,':wink:'));
});

Just thought it'd be worth offering a DOM solution:

E.g.

var div = document.createElement('div');
div.innerHTML = ":-)<pre>:-)</pre><blockquote>:-)</blockquote>";

replace(div, /:-\)/g, ":wink:", function(){

    // Custom filter function.
    // Returns false for <pre> elements.

    return this.nodeName.toLowerCase() !== 'pre';

});

div.innerHTML; // <== here's your new string!

And here's the replace function:

function replace(element, regex, replacement, filter) {

    var cur = element.firstChild;

    if (cur) do {

        if ( !filter || filter.call(cur) ) {

            if ( cur.nodeType == 1 ) {
                replace( cur, regex, replacement );
            } else {
                cur.data = cur.data.replace( regex, replacement );
            }

        }

    } while ( cur = cur.nextSibling );

}

Almost good: Your negative lookbehind and lookahead where not in the right position and need a slight adjustment:

/(?<!(<pre>)):-\)(?!(<\/pre>))/g
  1. Looks for all ":-)"
  2. ...but not if there is a <pre> behind (the regex cursor is!)
  3. ...but not if there is a </pre> before (the regex cursor is!)

as a side effect though: <pre>:-):-)</pre> works too but not <pre>:-):-):-)</pre>

https://regex101./r/CO0DAD/1

ps. this is a firefox 104 browser (could be different in others)

try with var regex = /:-)(?!(^)*</pre>)/g;

本文标签: regexHow to replace text not within a specificTag in JavaScriptStack Overflow