Substituir / regex de JavaScript

113

Dada esta função:

function Repeater(template) {

    var repeater = {

        markup: template,

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

    };

    return repeater;

};

Como faço a this.markup.replace()substituição globalmente? Aqui está o problema. Se eu usar assim:

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

O valor do alerta é "foobar $ TEST_ONE".

Se eu mudar Repeaterpara o seguinte, nada será substituído no Chrome:

function Repeater(template) {

    var repeater = {

        markup: template,

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

    };

    return repeater;

};

... e o alerta é $TEST_ONE $TEST_ONE.

testemunho
fonte

Respostas:

147

Você precisa fazer um escape duplo de quaisquer caracteres RegExp (uma vez para a barra na string e uma vez para a regexp):

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

Caso contrário, ele procura o fim da linha e 'TESTONE' (que nunca encontra).

Pessoalmente, não sou um grande fã de construir regexp usando strings por esse motivo. O nível de fuga necessário pode levar você a beber. Tenho certeza de que outros pensam de forma diferente e gostam de beber ao escrever regexes.

seth
fonte
Mas replace () recebe a regex como uma variável.
núcleo de
8
@Chris - Não acho que faça diferença se você usar /pattern/ou new RegExp("pattern").
harto
@seth, sua resposta funciona, mas não fornece uma solução para o código do OP. Como faço para chamar o código do OP?
Preto de
82

Em termos de interpretação de padrões, não há diferença entre as seguintes formas:

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

Se você quiser substituir uma string literal usando o replacemétodo, acho que você pode simplesmente passar uma string em vez de uma regexp para replace.

Caso contrário, você teria que escapar de quaisquer caracteres especiais regexp no padrão primeiro - talvez assim:

function reEscape(s) {
    return s.replace(/([.*+?^$|(){}\[\]])/mg, "\\$1");
}

// ...

var re = new RegExp(reEscape(pattern), "mg");
this.markup = this.markup.replace(re, value);
harto
fonte
12
Não sabia antes, que / padrão / é o mesmo que novo RegExp ("padrão"). Realmente ajudou!
Nik Sumeiko
1
Alguma razão para não usar uma lista branca em vez de uma lista negra? por exemplo: s.replace (/ (\ W) / g, '\\ $ 1')
greg.kindel
1
O primeiro formulário listado é melhor. É uma boa prática evitar a nova palavra-chave.
Druska
2
Não é preciso dizer que o literal da expressão regular (/ regex /) é o mesmo que RegExp ("regex"). No literal de expressão regular, o reverso solidus ('\') não precisa ser escapado ('\\') para que seja parte da expressão regular. Além disso, o literal de expressão regular pode ser compilado quando o script é analisado, e não sempre que a função é executada. Para corresponder a um solidus reverso, você pode escrever / \\ / ou RexExp ("\\\\").
John
31

Seu padrão regex deve ter o modificador g:

var pattern = /[somepattern]+/g;

observe o g no final. diz ao substituto para fazer uma substituição global.

Além disso, você não precisa usar o objeto RegExp, você pode construir seu padrão como acima. Padrão de exemplo:

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

um padrão é sempre cercado por / em cada lado - com modificadores após o / final, sendo o modificador g o global.

EDIT: Por que importa se o padrão é uma variável? No seu caso, funcionaria assim (observe que o padrão ainda é uma variável):

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

Mas você precisaria alterar sua função de substituição para esta:

this.markup = this.markup.replace(pattern, value);
Darko Z
fonte