ChatGPT解决这个技术问题 Extra ChatGPT

JavaScript replace/regex

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.


s
seth

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.


But replace() receives the regex as a variable.
@Chris - I don't think it makes a difference if you use /pattern/ or new RegExp("pattern").
@seth, Your answer works, but it does not provide a solution to the code from OP. How do I have to call OP's code?
h
harto

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 reEscape(s) {
    return s.replace(/([.*+?^$|(){}\[\]])/mg, "\\$1");
}

// ...

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

Didn't knew before, that /pattern/ is the same as new RegExp("pattern"). Really helped!
Any reason to not use a whitelist instead of a blacklist? eg: s.replace(/(\W)/g,'\\$1')
The first form listed is better. It's good practice to avoid the new keyword.
It's not accurate to say that the regular expression literal (/regex/) is the same as RegExp("regex"). In the regular expression literal, the reverse-solidus ('\') need not itself be escaped ('\\') in order for it to be part of the regular expression. Further, the regular expression literal can be compiled when the script is parsed rather than each time the function is executed. In order to match a reverse-solidus you can either write /\\/ or RexExp("\\\\").
D
Darko Z

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);