150 votes

Créer des RegExps à la volée à l'aide de variables de type chaîne de caractères

Supposons que je veuille rendre les éléments suivants réutilisables :

function replace_foo(target, replacement) {
   return target.replace("string_to_replace",replacement);
}

Je pourrais faire quelque chose comme ça :

function replace_foo(target, string_to_replace, replacement) {
   return target.replace(string_to_replace,replacement);
}

Avec les chaînes littérales, c'est assez facile. Mais que se passe-t-il si je veux être un peu plus délicat avec l'expression rationnelle ? Par exemple, disons que je veux remplacer tout mais string_to_replace . Instinctivement, j'essaierais d'étendre ce qui précède en faisant quelque chose du genre :

function replace_foo(target, string_to_replace, replacement) {
   return target.replace(/^string_to_replace/,replacement);
}

Cela ne semble pas fonctionner. Je pense qu'il pense que string_to_replace est une chaîne littérale, plutôt qu'une variable représentant une chaîne. Est-il possible de créer des regex JavaScript à la volée en utilisant des variables de type chaîne ? Quelque chose comme ça serait génial si c'est possible :

function replace_foo(target, string_to_replace, replacement) {
   var regex = "/^" + string_to_replace + "/";
   return target.replace(regex,replacement);
}

230voto

meder Points 81864

Il y a new RegExp(string, flags) donde flags sont g o i . Donc

'GODzilla'.replace( new RegExp('god', 'i'), '' )

évalue à

zilla

35 votes

Et omettez le / les délimiteurs de regex lorsque vous utilisez ce formulaire également.

117voto

bobince Points 270740

Avec les chaînes littérales, c'est assez facile.

Pas vraiment ! L'exemple ne fait que remplacer le premièrement l'apparition de string_to_replace . Plus couramment, vous souhaitez remplacer toutes les occurrences, auquel cas vous devez convertir la chaîne en une chaîne globale ( /.../g ) Vous pouvez le faire à partir d'une chaîne de caractères en utilisant la fonction new RegExp constructeur :

new RegExp(string_to_replace, 'g')

Le problème est que tous les caractères spéciaux de regex dans le littéral de la chaîne se comporteront de manière spéciale au lieu d'être des caractères normaux. Il faudrait les "backslash-escape" pour corriger cela. Malheureusement, il n'y a pas de fonction intégrée pour faire cela pour vous, alors en voici une que vous pouvez utiliser :

function escapeRegExp(s) {
    return s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
}

Notez également que lorsque vous utilisez un RegExp dans replace() la chaîne de remplacement a maintenant un caractère spécial aussi, $ . Il faut également l'échapper si l'on veut avoir un littéral $ dans votre texte de remplacement !

function escapeSubstitute(s) {
    return s.replace(/\$/g, '$$$$');
}

(Quatre $ parce que c'est lui-même une chaîne de remplacement - aïe !)

Vous pouvez maintenant mettre en œuvre le remplacement global de chaînes de caractères avec RegExp :

function replace_foo(target, string_to_replace, replacement) {
    var relit= escapeRegExp(string_to_replace);
    var sub= escapeSubstitute(replacement);
    var re= new RegExp(relit, 'g');
    return target.replace(re, sub);
}

Quelle douleur. Heureusement, si tout ce que vous voulez faire est un simple remplacement de chaîne de caractères sans aucune partie supplémentaire de regex, il existe un moyen plus rapide :

s.split(string_to_replace).join(replacement)

...et c'est tout. Il s'agit d'une expression idiomatique courante.

disons que je veux remplacer tout sauf la chaîne_à_remplacer

Cela signifie que vous voulez remplacer toutes les parties de texte qui ne participent pas à une correspondance avec la chaîne de caractères ? Un remplacement avec ^ ne le fait certainement pas, parce que ^ signifie un jeton de début de chaîne, pas une négation. ^ est seulement une négation dans [] groupes de caractères. Il existe également des anticipations négatives (?!...) mais cela pose des problèmes en JScript et vous devez donc généralement l'éviter.

Vous pouvez essayer de faire correspondre "tout ce qui va jusqu'à" la chaîne de caractères, et utiliser une fonction pour éliminer toute partie vide entre les chaînes de caractères correspondantes :

var re= new RegExp('(.*)($|'+escapeRegExp(string_to_find)+')')
return target.replace(re, function(match) {
    return match[1]===''? match[2] : replacement+match[2];
});

Là encore, une scission pourrait être plus simple :

var parts= target.split(string_to_match);
for (var i= parts.length; i-->0;)
    if (parts[i]!=='')
        parts[i]= replacement;
return parts.join(string_to_match);

15voto

Kent Points 136

Comme les autres l'ont dit, utilisez new RegExp(pattern, flags) pour faire ça. Il est important de noter que vous passerez des chaînes de caractères dans ce constructeur, donc chaque backslash devra être échappé. Si, par exemple, vous souhaitez que votre regex corresponde à une barre oblique inverse, vous devrez dire new RegExp('\\\\') alors que le littéral de l'expression rationnelle n'aurait besoin que d'être /\\/ . En fonction de l'utilisation que vous comptez en faire, vous devez vous méfier de la transmission des entrées utilisateur à une telle fonction sans prétraitement adéquat (échappement des caractères spéciaux, etc.) Sans cela, vos utilisateurs peuvent obtenir des résultats très inattendus.

5 votes

Cette réponse, bien que n'étant pas la plus détaillée, mentionne une crucial détail sur lequel je suis resté bloqué pendant une heure : échapper à toute séquence spéciale. Par exemple, je cherchais un mot commençant par un certain terme, donc la regex dont j'avais besoin était la suivante /\b[term]\B/ mais lors de sa construction, je dois appeler new RegExp("\\b"+ term + "\\B") . Une différence minime mais importante, et difficile à repérer puisqu'elle est utilisée directement comme une regex. fait fonctionnent comme prévu.

7voto

Kristof Neirynck Points 1347

Oui, vous pouvez.

https://developer.mozilla.org/en/JavaScript/Guide/Regular_Expressions

function replace_foo(target, string_to_replace, replacement) {
   var regex = new RegExp("^" + string_to_replace);
   return target.replace(regex, replacement);
}

3voto

Jack Allan Points 2142

Une solution très simple à ce problème est la suivante :

function replace(target, string_to_replace, replacement) {
  return target.split(string_to_replace).join(replacement);
}

Pas besoin de Regexes du tout

Il semble également être le plus rapide sur les navigateurs modernes. https://jsperf.com/replace-vs-split-join-vs-replaceall

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X