views:

2376

answers:

3

Given this function:

function Repeater(template) {

    var repeater = {

        markup: template,

        replace: function(pattern, value) {
            this.markup = this.markup.replace(pattern, value);
        }

    };

    return repeater;

};

How do I make this.markup.replace() replace globally? Here's the problem. If I use it like this:

alert(new Repeater("$TEST_ONE $TEST_ONE").replace("$TEST_ONE", "foobar").markup);

The alert's value is "foobar $TEST_ONE".

If I change Repeater to the following, then nothing in replaced in Chrome:

function Repeater(template) {

    var repeater = {

        markup: template,

        replace: function(pattern, value) {
            this.markup = this.markup.replace(new RegExp(pattern, "gm"), value);
        }

    };

    return repeater;

};

...and the alert is "$TEST_ONE $TEST_ONE".

+1  A: 

You need to double escape any RegExp characters (once for the slash in the string and once for the regexp):

  "$TESTONE $TESTONE".replace( new RegExp("\\$TESTONE","gm"),"foo")

Otherwise, it looks for the end of the line and 'TESTONE' (which it never finds).

Personally, I'm not a big fan of building regexp's using strings for this reason. The level of escaping that's needed could lead you to drink. I'm sure others feel differently though and like drinking when writing regexes.

seth
But replace() receives the regex as a variable.
Chris
Minor correction - `$` denotes end-of-line in a regexp.
harto
@Chris - I don't think it makes a difference if you use `/pattern/` or `new RegExp("pattern")`.
harto
@harto - thanks. space cadet over here.
seth
A: 

Your regex pattern should have the g modifier:

var pattern = /[somepattern]+/g;

notice the g at the end. it tells the replacer to do a global replace.

Also you dont need to use the RegExp object you can construct your pattern as above. Example pattern:

var pattern = /[0-9a-zA-Z]+/g;

a pattern is always surrounded by / on either side - with modifiers after the final /, the g modifier being the global.

EDIT: Why does it matter if pattern is a variable? In your case it would function like this (notice that pattern is still a variable):

var pattern = /[0-9a-zA-Z]+/g;
repeater.replace(pattern, "1234abc");

But you would need to change your replace function to this:

this.markup = this.markup.replace(pattern, value);
Darko Z
But replace() receives [somepattern] as a variable.
Chris
see edit .........
Darko Z
A: 

In terms of pattern interpretation, there's no difference between the following forms:

  • /pattern/
  • new RegExp("pattern")

If you want to replace a literal string using the replace method, I think you can just pass a string instead of a regexp to replace.

Otherwise, you'd have to escape any regexp special characters in the pattern first - maybe like so:

function escapeRegExpSpecialChars(pattern) {
    var specialChars = /(\.|\*|\+|\?|\^|\$|\||\(|\)|\[|\]|\{|\})/mg;
    return pattern.replace(specialChars, "\\$1");
}

// ...

var re = new RegExp(escapeRegExpSpecialChars(pattern), "mg");
this.markup = this.markup.replace(re, value);
harto