Est-il possible de faire quelque chose comme ça?
var pattern = /some regex segment/ + /* comment here */
/another segment/;
Ou dois-je utiliser la nouvelle syntaxe RegExp()
et concaténer une chaîne? Je préférerais utiliser le littéral car le code est à la fois plus évident et concis.
Voici comment créer une expression régulière sans utiliser la syntaxe littérale d'expression régulière. Cela vous permet de manipuler arbitrairement une chaîne avant qu'elle ne devienne un objet d'expression régulière:
var segment_part = "some bit of the regexp";
var pattern = new RegExp("some regex segment" + /*comment here */
segment_part + /* that was defined just now */
"another segment");
Si vous avez deux littéraux d'expression régulière, vous pouvez en fait les concaténer en utilisant cette technique:
var regex1 = /foo/g;
var regex2 = /bar/y;
var flags = (regex1.flags + regex2.flags).split("").sort().join("").replace(/(.)(?=.*\1)/g, "");
var regex3 = new RegExp(expression_one.source + expression_two.source, flags);
// regex3 is now /foobar/gy
C'est plus verbeux que d'avoir simplement l'expression un et deux comme étant des chaînes littérales au lieu d'expressions régulières littérales.
Juste concaténer au hasard des expressions régulières objets peut avoir des effets secondaires indésirables. Utilisez plutôt RegExp.source :
var r1 = /abc/g;
var r2 = /def/;
var r3 = new RegExp(r1.source + r2.source,
(r1.global ? 'g' : '')
+ (r1.ignoreCase ? 'i' : '') +
(r1.multiline ? 'm' : ''));
var m = 'test that abcdef and abcdef has a match?'.match(r3);
// m should contain 2 matches
Cela vous donnera également la possibilité de conserver les indicateurs d'expression régulière d'un RegExp précédent à l'aide des indicateurs RegExp standard.
Je ne suis pas tout à fait d'accord avec l'option "eval".
var xxx = /abcd/;
var yyy = /efgh/;
var zzz = new RegExp(eval(xxx)+eval(yyy));
donnera "// abcd // efgh //" qui n'est pas le résultat souhaité.
Utiliser une source comme
var zzz = new RegExp(xxx.source+yyy.source);
va donner "/ abcdefgh /" et c'est correct.
Logiquement, il n’est pas nécessaire d’ÉVALUER, vous connaissez votre EXPRESSION. Vous avez juste besoin de sa source ou comment il est écrit pas nécessairement sa valeur. En ce qui concerne les drapeaux, il vous suffit d’utiliser l’argument optionnel de RegExp.
Dans ma situation, je cours dans la question de ^ et $ étant utilisé dans plusieurs expressions que je tente de concaténer ensemble! Ces expressions sont des filtres de grammaire utilisés dans l’ensemble du programme. Maintenant, je ne voudrais pas utiliser certains d’eux ensemble pour traiter le cas des PRÉPOSITIONS. Je devrai peut-être "trancher" les sources pour supprimer le début et la fin de ^ (et/ou) $ :) À la vôtre, Alex.
Problème Si l'expression rationnelle contient des groupes de back-matching tels que\1.
var r = /(a|b)\1/ // Matches aa, bb but nothing else.
var p = /(c|d)\1/ // Matches cc, dd but nothing else.
Ensuite, le simple fait de contater les sources ne fonctionnera pas. En effet, la combinaison des deux est:
var rp = /(a|b)\1(c|d)\1/
rp.test("aadd") // Returns false
La solution: Nous comptons d'abord le nombre de groupes correspondants dans la première expression rationnelle, puis pour chaque jeton de correspondance dans la seconde, nous l'incrémentons du nombre de groupes correspondants.
function concatenate(r1, r2) {
var count = function(r, str) {
return str.match(r).length;
}
var numberGroups = /([^\\]|^)(?=\((?!\?:))/g; // Home-made regexp to count groups.
var offset = count(numberGroups, r1.source);
var escapedMatch = /[\\](?:(\d+)|.)/g; // Home-made regexp for escaped literals, greedy on numbers.
var r2newSource = r2.source.replace(escapedMatch, function(match, number) { return number?"\\"+(number-0+offset):match; });
return new RegExp(r1.source+r2newSource,
(r1.global ? 'g' : '')
+ (r1.ignoreCase ? 'i' : '')
+ (r1.multiline ? 'm' : ''));
}
Tester:
var rp = concatenate(r, p) // returns /(a|b)\1(c|d)\2/
rp.test("aadd") // Returns true
À condition que:
/this/g
plutôt que new RegExp('this', 'g')
;Ensuite, vous pouvez écrire de cette façon:
var regexParts =
[
/\b(\d+|null)\b/,// Some comments.
/\b(true|false)\b/,
/\b(new|getElementsBy(?:Tag|Class|)Name|arguments|getElementById|if|else|do|null|return|case|default|function|typeof|undefined|instanceof|this|document|window|while|for|switch|in|break|continue|length|var|(?:clear|set)(?:Timeout|Interval))(?=\W)/,
/(\$|jQuery)/,
/many more patterns/
],
regexString = regexParts.map(function(x){return x.source}).join('|'),
regexPattern = new RegExp(regexString, 'g');
vous pouvez alors faire quelque chose comme:
string.replace(regexPattern, function()
{
var m = arguments,
Class = '';
switch(true)
{
// Numbers and 'null'.
case (Boolean)(m[1]):
m = m[1];
Class = 'number';
break;
// True or False.
case (Boolean)(m[2]):
m = m[2];
Class = 'bool';
break;
// True or False.
case (Boolean)(m[3]):
m = m[3];
Class = 'keyword';
break;
// $ or 'jQuery'.
case (Boolean)(m[4]):
m = m[4];
Class = 'dollar';
break;
// More cases...
}
return '<span class="' + Class + '">' + m + '</span>';
})
Dans mon cas particulier (un éditeur ressemblant à un code-miroir), il est beaucoup plus facile d’effectuer une grande regex plutôt que beaucoup de remplacements comme suit, car chaque fois que je remplace une balise html pour envelopper une expression, le motif suivant être plus difficile à cibler sans affecter la balise html elle-même (et sans le bon lookbehind qui n'est malheureusement pas supporté en javascript):
.replace(/(\b\d+|null\b)/g, '<span class="number">$1</span>')
.replace(/(\btrue|false\b)/g, '<span class="bool">$1</span>')
.replace(/\b(new|getElementsBy(?:Tag|Class|)Name|arguments|getElementById|if|else|do|null|return|case|default|function|typeof|undefined|instanceof|this|document|window|while|for|switch|in|break|continue|var|(?:clear|set)(?:Timeout|Interval))(?=\W)/g, '<span class="keyword">$1</span>')
.replace(/\$/g, '<span class="dollar">$</span>')
.replace(/([\[\](){}.:;,+\-?=])/g, '<span class="ponctuation">$1</span>')
Vous pourriez faire quelque chose comme:
function concatRegex(...segments) {
return new RegExp(segments.join(''));
}
Les segments seraient des chaînes (plutôt que des littéraux de regex) transmises en tant qu'arguments séparés.
Il serait préférable d'utiliser la syntaxe littérale aussi souvent que possible. Il est plus court, plus lisible et vous n'avez pas besoin de guillemets d'échappement ni de retours en double. D'après "Patterns Javascript", Stoyan Stefanov 2010.
Mais utiliser Nouveau peut être le seul moyen de concaténer.
J'éviterais eval. Ce n'est pas prudent.
Utilisez le constructeur avec 2 paramètres et évitez le problème avec le '/' suivi:
var re_final = new RegExp("\\" + ".", "g"); // constructor can have 2 params!
console.log("...finally".replace(re_final, "!") + "\n" + re_final +
" works as expected..."); // !!!finally works as expected
// meanwhile
re_final = new RegExp("\\" + "." + "g"); // appends final '/'
console.log("... finally".replace(re_final, "!")); // ...finally
console.log(re_final, "does not work!"); // does not work
Vous devrez utiliser le nouveau RegExp! -)
Non, la manière littérale n'est pas supportée. Vous devrez utiliser RegExp.