É possível fazer algo assim?
var pattern = /some regex segment/ + /* comment here */
/another segment/;
Ou tenho que usar nova RegExp()
sintaxe e concatenar uma string? Eu preferiria usar o literal, pois o código é mais evidente e conciso.
É possível fazer algo assim?
var pattern = /some regex segment/ + /* comment here */
/another segment/;
Ou tenho que usar nova RegExp()
sintaxe e concatenar uma string? Eu preferiria usar o literal, pois o código é mais evidente e conciso.
Respostas:
Aqui está como criar uma expressão regular sem usar a sintaxe literal da expressão regular. Isso permite que você faça a manipulação de string arbitrária antes que ela se torne um objeto de expressão regular:
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");
Se você possui dois literais de expressão regular, é possível concatená-los usando esta técnica:
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
É apenas mais prolixo do que apenas ter a expressão um e dois sendo strings literais em vez de expressões regulares literais.
new RegExp(/(/.source + /.*/.source + /)?/.source);
parece não funcionar.
expression_one
? Você quer dizer regex1
?
Apenas concatenar aleatoriamente objetos de expressões regulares pode ter alguns efeitos colaterais adversos. Use o 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' : ''));
console.log(r3);
var m = 'test that abcdef and abcdef has a match?'.match(r3);
console.log(m);
// m should contain 2 matches
Isso também permitirá que você mantenha os sinalizadores de expressão regular de um RegExp anterior usando os sinalizadores RegExp padrão.
RegExp.prototype.flags
Não concordo totalmente com a opção "eval".
var xxx = /abcd/;
var yyy = /efgh/;
var zzz = new RegExp(eval(xxx)+eval(yyy));
dará "// abcd // efgh //", que não é o resultado pretendido.
Usando fonte como
var zzz = new RegExp(xxx.source+yyy.source);
dará "/ abcdefgh /" e isso está correto.
Logicamente, não há necessidade de AVALIAR, você conhece sua EXPRESSÃO. Você só precisa da sua FONTE ou de como ela está escrita, não necessariamente do seu valor. Quanto aos sinalizadores, você só precisa usar o argumento opcional de RegExp.
Na minha situação, eu corro na questão de ^ e $ sendo usados em várias expressões que estou tentando concatenar juntos! Essas expressões são filtros gramaticais usados em todo o programa. Agora não quero usar alguns deles juntos para lidar com o caso de PREPOSIÇÕES. Talvez eu precise "cortar" as fontes para remover o início e o final ^ (e / ou) $ :) Saúde, Alex.
var regex = "\.\..*"
Problema Se o regexp contiver grupos de correspondência retroativa como \ 1.
var r = /(a|b)\1/ // Matches aa, bb but nothing else.
var p = /(c|d)\1/ // Matches cc, dd but nothing else.
Então apenas contatenar as fontes não funcionará. De fato, a combinação dos dois é:
var rp = /(a|b)\1(c|d)\1/
rp.test("aadd") // Returns false
A solução: primeiro, contamos o número de grupos correspondentes no primeiro regex; depois, para cada token de correspondência retroativa no segundo, incrementamos o número de grupos correspondentes.
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' : ''));
}
Teste:
var rp = concatenate(r, p) // returns /(a|b)\1(c|d)\2/
rp.test("aadd") // Returns true
function concatenateList() { var res = arguments[0]; for(var i = 1; i < arguments.length; i++) { res = concatenate(res, arguments[i]); } return res; }
Seria preferível usar a sintaxe literal o mais rápido possível. É mais curto, mais legível e você não precisa de aspas de escape ou de escapes duplos. De "Padrões Javascript", Stoyan Stefanov 2010.
Mas usar Novo pode ser a única maneira de concatenar.
Eu evitaria avaliar. Não é seguro.
Fornecendo:
/this/g
do que new RegExp('this', 'g')
;Então você pode escrever desta maneira:
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');
você pode fazer algo como:
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>';
})
No meu caso específico (um editor semelhante ao código-espelho), é muito mais fácil executar uma grande regex, em vez de muitas substituições como a seguir, sempre que eu substituo por uma tag html para quebrar uma expressão, o próximo padrão será ser mais difícil de segmentar sem afetar a própria tag html (e sem a boa aparência que infelizmente não é suportada em 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>')
Você poderia fazer algo como:
function concatRegex(...segments) {
return new RegExp(segments.join(''));
}
Os segmentos seriam seqüências de caracteres (em vez de literais de regex) passadas como argumentos separados.
Use o construtor com 2 parâmetros e evite o problema de arrastar '/':
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
Você pode concat fonte de regex da classe literal e RegExp:
var xxx = new RegExp(/abcd/);
var zzz = new RegExp(xxx.source + /efgh/.source);
a maneira mais fácil para mim seria concatenar as fontes, ex .:
a = /\d+/
b = /\w+/
c = new RegExp(a.source + b.source)
o valor c resultará em:
/ \ d + \ w + /
let regexSegment1 = String.raw`\s*hello\s*`