JavaScript remplacer / regex

113

Compte tenu de cette fonction:

function Repeater(template) {

    var repeater = {

        markup: template,

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

    };

    return repeater;

};

Comment faire this.markup.replace()remplacer globalement? Voici le problème. Si je l'utilise comme ça:

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

La valeur de l'alerte est "foobar $ TEST_ONE".

Si je change Repeatercomme suit, rien n'est remplacé dans Chrome:

function Repeater(template) {

    var repeater = {

        markup: template,

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

    };

    return repeater;

};

... et l'alerte est $TEST_ONE $TEST_ONE.

coeur
la source

Réponses:

147

Vous devez double échapper tous les caractères RegExp (une fois pour la barre oblique dans la chaîne et une fois pour l'expression rationnelle):

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

Sinon, il recherche la fin de la ligne et «TESTONE» (qu'il ne trouve jamais).

Personnellement, je ne suis pas un grand fan de la création d'expressions rationnelles en utilisant des chaînes pour cette raison. Le niveau d'évasion nécessaire pourrait vous amener à boire. Je suis sûr que les autres se sentent différemment et aiment boire lorsqu'ils écrivent des expressions régulières.

seth
la source
Mais replace () reçoit l'expression rationnelle comme une variable.
core
8
@Chris - Je ne pense pas que cela fasse une différence si vous utilisez /pattern/ou new RegExp("pattern").
harto
@seth, votre réponse fonctionne, mais elle ne fournit pas de solution au code d'OP. Comment dois-je appeler le code OP?
Black
82

En termes d'interprétation des modèles, il n'y a aucune différence entre les formes suivantes:

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

Si vous souhaitez remplacer une chaîne littérale en utilisant la replaceméthode, je pense que vous pouvez simplement passer une chaîne au lieu d'une expression rationnelle à replace.

Sinon, vous devrez d'abord échapper tous les caractères spéciaux de l'expression rationnelle dans le modèle - peut-être comme ceci:

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

// ...

var re = new RegExp(reEscape(pattern), "mg");
this.markup = this.markup.replace(re, value);
harto
la source
12
Je ne savais pas avant, que / pattern / est identique au nouveau RegExp ("pattern"). Vraiment aidé!
Nik Sumeiko
1
Une raison pour ne pas utiliser une liste blanche au lieu d'une liste noire? par exemple: s.replace (/ (\ W) / g, '\\ $ 1')
greg.kindel
1
La première forme répertoriée est meilleure. Il est recommandé d'éviter le nouveau mot-clé.
Druska
2
Il n'est pas exact de dire que le littéral d'expression régulière (/ regex /) est le même que RegExp ("regex"). Dans le littéral d'expression régulière, le solidus inversé ('\') n'a pas besoin d'être lui-même échappé ('\\') pour qu'il fasse partie de l'expression régulière. En outre, le littéral d'expression régulière peut être compilé lorsque le script est analysé plutôt qu'à chaque fois que la fonction est exécutée. Pour faire correspondre un solidus inversé, vous pouvez écrire / \\ / ou RexExp ("\\\\").
John
31

Votre modèle regex doit avoir le modificateur g:

var pattern = /[somepattern]+/g;

remarquez le g à la fin. il indique au remplaçant d'effectuer un remplacement global.

De plus, vous n'avez pas besoin d'utiliser l'objet RegExp, vous pouvez construire votre modèle comme ci-dessus. Exemple de modèle:

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

un motif est toujours entouré par / de chaque côté - avec des modificateurs après le / final, le modificateur g étant le global.

EDIT: Pourquoi est-ce important si le motif est une variable? Dans votre cas, cela fonctionnerait comme ceci (notez que le modèle est toujours une variable):

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

Mais vous devrez changer votre fonction de remplacement en ceci:

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