web-dev-qa-db-fra.com

Conversion de chaîne de saisie utilisateur en expression régulière

Je conçois un testeur d'expressions régulières en HTML et JavaScript. L'utilisateur entrera une regex, une chaîne de caractères et choisira la fonction avec laquelle il souhaite tester (recherche, correspondance, remplacement, etc.) via le bouton radio et le programme affichera les résultats lorsque cette fonction sera exécutée avec les arguments spécifiés. Naturellement, il y aura des zones de texte supplémentaires pour les arguments supplémentaires à remplacer, etc.

Mon problème est d'obtenir la chaîne de l'utilisateur et de la transformer en une expression régulière. Si je dis qu'ils n'ont pas besoin d'avoir // autour de la regex qu'ils entrent, ils ne peuvent pas définir d'indicateurs, comme g et i. Ils doivent donc avoir le // autour de l'expression, mais comment puis-je convertir cette chaîne en regex? Il ne peut pas s'agir d'un littéral puisqu'il s'agit d'une chaîne et je ne peux pas le transmettre au constructeur RegExp car ce n'est pas une chaîne sans les // '. Existe-t-il un autre moyen de transformer une chaîne d'entrée utilisateur en une expression rationnelle? Devrai-je analyser la chaîne et les drapeaux de l'expression rationnelle avec les // puis le construire d'une autre manière? Devrais-je les faire entrer une chaîne, puis entrer les drapeaux séparément?

308
Gordon Gustafson

Utilisez le constructeur d'objet RegExp pour créer une expression régulière à partir d'une chaîne:

var re = new RegExp("a|b", "i");
// same as
var re = /a|b/i;
572
Gumbo
var flags = inputstring.replace(/.*\/([gimy]*)$/, '$1');
var pattern = inputstring.replace(new RegExp('^/(.*?)/'+flags+'$'), '$1');
var regex = new RegExp(pattern, flags);

ou

var match = inputstring.match(new RegExp('^/(.*?)/([gimy]*)$'));
// sanity check here
var regex = new RegExp(match[1], match[2]);
65
Anonymous

Voici un one-liner: str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')

Je l'ai eu du module NPM de --- (escape-string-regexp .

L'essayer:

escapeStringRegExp.matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g;
function escapeStringRegExp(str) {
    return str.replace(escapeStringRegExp.matchOperatorsRe, '\\$&');
}

console.log(new RegExp(escapeStringRegExp('example.com')));
// => /example\.com/
15
Rivenfall

Utilisez le constructeur d'objet JavaScript RegExp .

var re = new RegExp("\\w+");
re.test("hello");

Vous pouvez transmettre des indicateurs en tant que deuxième argument de chaîne au constructeur. Voir la documentation pour plus de détails.

14
Ayman Hourieh

Dans mon cas, les entrées utilisateur sont parfois entourées de délimiteurs et parfois non. donc j'ai ajouté un autre cas ..

var regParts = inputstring.match(/^\/(.*?)\/([gim]*)$/);
if (regParts) {
    // the parsed pattern had delimiters and modifiers. handle them. 
    var regexp = new RegExp(regParts[1], regParts[2]);
} else {
    // we got pattern string without delimiters
    var regexp = new RegExp(inputstring);
}
9
staabm

Cela fonctionnera également lorsque la chaîne n'est pas valide ou ne contient pas d'indicateur, etc.:

function regExpFromString(q) {
  let flags = q.replace(/.*\/([gimuy]*)$/, '$1');
  if (flags === q) flags = '';
  let pattern = (flags ? q.replace(new RegExp('^/(.*?)/' + flags + '$'), '$1') : q);
  try { return new RegExp(pattern, flags); } catch (e) { return null; }
}

console.log(regExpFromString('\\bword\\b'));
console.log(regExpFromString('\/\\bword\\b\/gi'));
            
2
kofifus

Je vous suggère également d'ajouter des cases à cocher séparées ou un champ de texte pour les drapeaux spéciaux. Ainsi, il est clair que l'utilisateur n'a pas besoin d'ajouter de // '. Dans le cas d'un remplacement, fournissez deux champs de texte. Cela vous facilitera grandement la vie.

Pourquoi? Sinon, certains utilisateurs ajouteront //, d'autres non. Et certains feront une erreur de syntaxe. Ensuite, après avoir supprimé les // ', vous pouvez vous retrouver avec une expression rationnelle syntaxiquement valide qui ne ressemble en rien à l'intention de l'utilisateur, ce qui entraîne un comportement étrange (du point de vue de l'utilisateur).

2
Stephan202

Grâce aux réponses précédentes, ce bloc constitue une solution générique pour appliquer une chaîne configurable à un RegEx .. afin de filtrer du texte:

var permittedChars = '^a-z0-9 _,.?!@+<>';
permittedChars = '[' + permittedChars + ']';

var flags = 'gi';
var strFilterRegEx = new RegExp(permittedChars, flags);

log.debug ('strFilterRegEx: ' + strFilterRegEx);

strVal = strVal.replace(strFilterRegEx, '');
// this replaces hard code solt:
// strVal = strVal.replace(/[^a-z0-9 _,.?!@+]/ig, '');
1
Gene Bo

Vous pouvez demander des drapeaux en utilisant des cases à cocher, puis procédez comme suit:

var userInput = formInput;
var flags = '';
if(formGlobalCheckboxChecked) flags += 'g';
if(formCaseICheckboxChecked) flags += 'i';
var reg = new RegExp(userInput, flags);
1
Pim Jager

Si vous vraiment voulez convertir une chaîne en regex, essayez la fonction suivante:

function String2Regex(s){return new RegExp(s.match(/\/(.+)\/.*/)[1], s.match(/\/.+\/(.*)/)[1]);}

Vous pouvez l'utiliser comme ceci:

"abc".match(String2Regex("/a/g"))
> ["a"]

Pour référence, voici la version formatée et plus moderne:

const String2Regex = str => {
  // Main regex
  const main = str.match(/\/(.+)\/.*/)[1]

  // Regex options
  const options = str.match(/\/.+\/(.*)/)[1]

  // Return compiled regex
  return new RegExp(main, options)
}
0
Richie Bendall