Comment utilisez-vous une variable dans une expression régulière?

1380

Je voudrais créer une String.replaceAll()méthode en JavaScript et je pense que l'utilisation d'une expression régulière serait la manière la plus laconique de le faire. Cependant, je ne peux pas comprendre comment passer une variable dans une expression régulière. Je peux déjà le faire, ce qui remplacera toutes les instances de "B"with "A".

"ABABAB".replace(/B/g, "A");

Mais je veux faire quelque chose comme ça:

String.prototype.replaceAll = function(replaceThis, withThis) {
    this.replace(/replaceThis/g, withThis);
};

Mais évidemment, cela ne remplacera que le texte "replaceThis"... alors comment puis-je passer cette variable dans ma chaîne d'expression régulière?

JC Grubbs
la source
9
Notez que nous travaillons actuellement sur l'ajout de cette fonctionnalité à JavaScript. Si vous avez une opinion à ce sujet, veuillez participer à la discussion.
Benjamin Gruenbaum

Réponses:

1842

Au lieu d'utiliser la /regex/gsyntaxe, vous pouvez construire un nouvel objet RegExp :

var replace = "regex";
var re = new RegExp(replace,"g");

Vous pouvez créer dynamiquement des objets regex de cette façon. Ensuite, vous ferez:

"mystring".replace(re, "newstring");
Eric Wendelin
la source
272
Si vous avez besoin d'utiliser une expression comme /\/word\:\w*$/, assurez - vous d'échapper à vos antislashs: new RegExp( '\\/word\\:\\w*$' ).
Jonathan Swinney
2
@gravityboy Vous pouvez faire ('' + myNumber) .replace (/ 10 / g, 'a') ou si vous voulez des nombres hexadécimaux, vous pouvez faire parseInt ('' + myNumber, 16) pour convertir en hexadécimal à partir de la décimale.
Eric Wendelin
29
La question suggère que le RegEx n'est utilisé que pour effectuer un remplacement de chaîne constant. Donc, cette réponse est fausse car elle échouerait si la chaîne contient des méta caractères RegEx. Il est triste a voté ce haut, fera beaucoup de maux de tête ...
dronus
16
Un exemple de ce passage d'une variable en ferait une bonne réponse. J'ai encore du mal après avoir lu ça.
Goose
3
@JonathanSwinney: /n'a pas de signification particulière si vous construisez une expression régulière à partir d'une chaîne, vous n'avez donc pas besoin de l'échapper. /\/word\:\w*$/devrait êtrenew RegExp('/word\\:\\w*$')
Dávid Horváth
211

Comme Eric Wendelin l'a mentionné, vous pouvez faire quelque chose comme ceci:

str1 = "pattern"
var re = new RegExp(str1, "g");
"pattern matching .".replace(re, "regex");

Cela donne "regex matching .". Cependant, il échouera si str1 l'est ".". Vous vous attendriez à ce que le résultat soit "pattern matching regex", en remplaçant la période par "regex", mais il se révélera être ...

regexregexregexregexregexregexregexregexregexregexregexregexregexregexregexregexregexregex

Cela est dû au fait que, bien qu'il s'agisse d' "."une chaîne, dans le constructeur RegExp, il est toujours interprété comme une expression régulière, ce qui signifie tout caractère sans saut de ligne, ce qui signifie chaque caractère de la chaîne. À cet effet, la fonction suivante peut être utile:

 RegExp.quote = function(str) {
     return str.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
 };

Ensuite, vous pouvez faire:

str1 = "."
var re = new RegExp(RegExp.quote(str1), "g");
"pattern matching .".replace(re, "regex");

céder "pattern matching regex".

Gracenotes
la source
4
Vous savez que le premier paramètre à remplacer peut être une chaîne normale et ne doit pas nécessairement être une expression rationnelle? str1 = "."; alert ("pattern matching.". replace (str1, "string"));
du
@some: bien sûr. C'est parce que l'exemple ci-dessus est trivial. Lorsque vous devez rechercher ou remplacer un modèle combiné avec une chaîne régulière, faites str.match (new RegExp ("https?: //" + RegExp.escape (myDomainName)), par exemple. Il est ennuyeux que la fonction d'échappement soit pas construit.
Gracenotes
(suite) De plus, JC Grubbs avait apparemment besoin d'un remplacement mondial; l'implémentation d'un remplacement global par String.replace (String, String) peut être lente pour une entrée volumineuse. Je dis juste, les deux premières solutions sont boguées et échoueront inattendues sur certaines entrées.
Gracenotes du
4
developer.mozilla.org/en-US/docs/JavaScript/Guide/… offre une fonction similaire, mais ils excluent -et incluent =!:/.
chbrown
8
Le terme correct est "évasion", pas "citation". Juste BTW.
Lawrence Dol
118

"ABABAB".replace(/B/g, "A");

Comme toujours: n'utilisez pas l'expression régulière sauf si vous le devez. Pour un simple remplacement de chaîne, l'idiome est:

'ABABAB'.split('B').join('A')

Ensuite, vous n'avez pas à vous soucier des problèmes de citation mentionnés dans la réponse de Gracenotes.

bobince
la source
11
Et avez-vous mesuré que c'est plus rapide que l'expression régulière?
Mitar
3
Cela semble préférable, en particulier lorsque vous devez faire correspondre des caractères d'expressions spéciales comme '.'
Krease
1
Uhm ... Ne divise pas aussi prendre un RegExp; si oui, ne causerait-il pas le même problème? Quoi qu'il en soit ... .split (). Join () peut être plus lent sur certaines plates-formes, car il s'agit de deux opérations, tandis que .replace () est une opération et peut être optimisé.
5
@ PacMan--: les deux splitet replacepeuvent prendre une chaîne ou un RegExpobjet. Le problème que replacecela splitne pose pas est que lorsque vous utilisez une chaîne, vous n'obtenez qu'un seul remplacement.
bobince
1
référence ici: jsperf.com/replace-vs-split-join-vs-replaceall/23
Wagner da Silva
38

Si vous voulez obtenir TOUTES les occurrences ( g), soyez insensible à la casse ( i) et utilisez des limites pour que ce ne soit pas un mot dans un autre mot ( \\b):

re = new RegExp(`\\b${replaceThis}\\b`, 'gi');

Exemple:

let inputString = "I'm John, or johnny, but I prefer john.";
let replaceThis = "John";
let re = new RegExp(`\\b${replaceThis}\\b`, 'gi');
console.log(inputString.replace(re, "Jack")); // I'm Jack, or johnny, but I prefer Jack.
JBallin
la source
Merci! (afaict, la vôtre est la seule réponse explicite avec rxune interpolation Emacs / -style, via des chaînes de modèle.)
sam boosalis
34

Pour tous ceux qui cherchent à utiliser une variable avec la méthode de correspondance , cela a fonctionné pour moi

var alpha = 'fig';
'food fight'.match(alpha + 'ht')[0]; // fight
Steven Penny
la source
31

Cette:

var txt=new RegExp(pattern,attributes);

est équivalent à ceci:

var txt=/pattern/attributes;

Voir http://www.w3schools.com/jsref/jsref_obj_regexp.asp .

Jeremy Ruten
la source
20
oui, mais dans le premier exemple, il utilise patterncomme variable, dans le 2ème comme une chaîne
vladkras
20
this.replace( new RegExp( replaceThis, 'g' ), withThis );
tvanfosson
la source
J'aime cette réponse car elle ne crée pas la variable supplémentaire (& inutile).
Wick
14

Vous voulez construire l'expression régulière dynamiquement et pour cela, la bonne solution est d'utiliser le new RegExp(string)constructeur. Pour que le constructeur traite les caractères spéciaux littéralement , vous devez leur échapper. Il y a une fonction intégrée dans le widget de saisie semi-automatique jQuery UI appelée $.ui.autocomplete.escapeRegex:

[...] vous pouvez utiliser la $.ui.autocomplete.escapeRegexfonction intégrée. Cela prendra un seul argument de chaîne et échappera à tous les caractères regex, ce qui rend le résultat sûr à passer new RegExp().

Si vous utilisez jQuery UI, vous pouvez utiliser cette fonction ou copier sa définition à partir de la source :

function escapeRegex( value ) {
    return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
}

Et utilisez-le comme ceci:

"[z-a][z-a][z-a]".replace(new RegExp(escapeRegex("[z-a]"), "g"), "[a-z]");
//            escapeRegex("[z-a]")       -> "\[z\-a\]"
// new RegExp(escapeRegex("[z-a]"), "g") -> /\[z\-a\]/g
// end result                            -> "[a-z][a-z][a-z]"
Salman A
la source
9
String.prototype.replaceAll = function (replaceThis, withThis) {
   var re = new RegExp(replaceThis,"g"); 
   return this.replace(re, withThis);
};
var aa = "abab54..aba".replaceAll("\\.", "v");

Testez avec cet outil

unigogo
la source
5
String.prototype.replaceAll = function(a, b) {
    return this.replace(new RegExp(a.replace(/([.?*+^$[\]\\(){}|-])/ig, "\\$1"), 'ig'), b)
}

Testez-le comme:

var whatever = 'Some [b]random[/b] text in a [b]sentence.[/b]'

console.log(whatever.replaceAll("[", "<").replaceAll("]", ">"))
MetalGodwin
la source
4

Voici une autre implémentation replaceAll:

    String.prototype.replaceAll = function (stringToFind, stringToReplace) {
        if ( stringToFind == stringToReplace) return this;
        var temp = this;
        var index = temp.indexOf(stringToFind);
        while (index != -1) {
            temp = temp.replace(stringToFind, stringToReplace);
            index = temp.indexOf(stringToFind);
        }
        return temp;
    };
scripto
la source
4

Et la version coffeescript de la réponse de Steven Penny, puisque c'est le résultat n ° 2 de Google .... même si le café est juste javascript avec beaucoup de caractères supprimés ...;)

baz = "foo"
filter = new RegExp(baz + "d")
"food fight".match(filter)[0] // food

et dans mon cas particulier

robot.name=hubot
filter = new RegExp(robot.name)
if msg.match.input.match(filter)
  console.log "True!"
enthousiaste
la source
pourquoi un downvote? coffeescript -IS- javascript avec sa propre syntaxe spécifique.
vif
robot.name=hubotn'est pas javascript.
codepleb
3

Bien que vous puissiez créer des RegExp créés dynamiquement (selon les autres réponses à cette question), je ferai écho à mon commentaire d'un article similaire : La forme fonctionnelle de String.replace () est extrêmement utile et dans de nombreux cas, réduit le besoin de objets RegExp créés dynamiquement. (qui sont un peu pénibles, car vous devez exprimer l'entrée du constructeur RegExp sous forme de chaîne plutôt que d'utiliser le format littéral slash / [AZ] + / regexp)

Jason S
la source
3

Pour satisfaire mon besoin d'insérer une variable / alias / fonction dans une expression régulière, voici ce que j'ai trouvé:

oldre = /xx\(""\)/;
function newre(e){
    return RegExp(e.toString().replace(/\//g,"").replace(/xx/g, yy), "g")
};

String.prototype.replaceAll = this.replace(newre(oldre), "withThis");

où 'oldre' est l'expression rationnelle d'origine que je veux insérer une variable, 'xx' est l'espace réservé pour cette variable / alias / fonction, et 'yy' est le nom de variable, l'alias ou la fonction réelle.

Alex Li
la source
2

Vous pouvez l'utiliser si $ 1 ne fonctionne pas avec vous

var pattern = new RegExp("amman","i");
"abc Amman efg".replace(pattern,"<b>"+"abc Amman efg".match(pattern)[0]+"</b>");
Alnamrouti à prix réduit
la source
1

Vous pouvez toujours utiliser à indexOfplusieurs reprises:

String.prototype.replaceAll = function(substring, replacement) {
    var result = '';
    var lastIndex = 0;

    while(true) {
        var index = this.indexOf(substring, lastIndex);
        if(index === -1) break;
        result += this.substring(lastIndex, index) + replacement;
        lastIndex = index + substring.length;
    }

    return result + this.substring(lastIndex);
};

Cela ne va pas dans une boucle infinie lorsque le remplacement contient la correspondance.

Ry-
la source
1

Votre solution est ici:

Passez une variable à une expression régulière.

Celui que j'ai mis en œuvre consiste à prendre la valeur d'un champ de texte qui est celui que vous souhaitez remplacer et un autre est le champ de texte "remplacer par", en obtenant la valeur du champ de texte dans une variable et en définissant la variable sur RegExp fonction à remplacer. Dans mon cas, j'utilise Jquery, vous pouvez également le faire uniquement avec JavaScript.

Code JavaScript:

  var replace =document.getElementById("replace}"); // getting a value from a text field with I want to replace
  var replace_with = document.getElementById("with"); //Getting the value from another text fields with which I want to replace another string.

  var sRegExInput = new RegExp(replace, "g");    
  $("body").children().each(function() {
    $(this).html($(this).html().replace(sRegExInput,replace_with));
  });

Ce code est sur événement Onclick d'un bouton, vous pouvez le mettre dans une fonction à appeler.

Alors maintenant, vous pouvez passer une variable dans la fonction de remplacement.

Ajit Hogade
la source
Votre variable replace_with contiendra l'élément DOM et non la valeur elle
Ben Taliadoros
1

Cette fonction auto-appelée itérera sur replacerItems à l'aide d'un index et changera globalement replacerItems [index] sur la chaîne à chaque passage.

  const replacerItems = ["a", "b", "c"];    

    function replacer(str, index){
          const item = replacerItems[index];
          const regex = new RegExp(`[${item}]`, "g");
          const newStr = str.replace(regex, "z");
          if (index < replacerItems.length - 1) {
            return replacer(newStr, index + 1);
          }
          return newStr;
    }

// console.log(replacer('abcdefg', 0)) will output 'zzzdefg'

la source
0

Aucune de ces réponses n'était claire pour moi. J'ai finalement trouvé une bonne explication sur http://burnignorance.com/php-programming-tips/how-to-use-a-variable-in-replace-function-of-javascript/

La réponse simple est:

var search_term = new RegExp(search_term, "g");    
text = text.replace(search_term, replace_term);

Par exemple:

$("button").click(function() {
  Find_and_replace("Lorem", "Chocolate");
  Find_and_replace("ipsum", "ice-cream");
});

function Find_and_replace(search_term, replace_term) {
  text = $("textbox").html();
  var search_term = new RegExp(search_term, "g");
  text = text.replace(search_term, replace_term);
  $("textbox").html(text);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textbox>
  Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum
</textbox>
<button>Click me</button>

Paul Chris Jones
la source
1
Vous écrasez une variable de fermeture, inutile de l'utiliser varici. De plus, si vous passez \bou \1cela casserait.
CyberAP
0

Pour plusieurs remplacements sans expressions régulières, je suis allé avec ce qui suit:

      let str = "I am a cat man. I like cats";
      let find = "cat";
      let replace = "dog";


      // Count how many occurrences there are of the string to find 
      // inside the str to be examined.
      let findCount = str.split(find).length - 1;

      let loopCount = 0;

      while (loopCount < findCount) 
      {
        str = str.replace(find, replace);
        loopCount = loopCount + 1;
      }  

      console.log(str);
      // I am a dog man. I like dogs

La partie importante de la solution a été trouvée ici

John Shearing
la source