我怎样才能在JavaScript中连接正则expression式文字?
有没有可能做这样的事情?
var pattern = /some regex segment/ + /* comment here */ /another segment/;
或者我必须使用新的RegExp()
语法并连接string? 我宁愿使用文字,因为代码更加不言而喻和简洁。
这里是如何创build一个正则expression式,而不使用正则expression式的文字语法。 这可以让你在变成正则expression式对象之前进行任意的string操作:
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");
如果你有两个正则expression式字面值,你可以使用这种方法将它们连接起来:
var expression_one = /foo/; var expression_two = /bar/; var expression_three = new RegExp(expression_one.source + expression_two.source);
这不完全是一个好的解决scheme,因为你失去了在expression_one和expression_two上设置的标志,而且比只有expression式1和2是文字string而不是文字正则expression式更罗嗦。
随机连接正则expression式对象会产生一些不良的副作用。 改用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
这也将使您能够使用标准RegExp标志保留以前的RegExp中的正则expression式标志。
的jsfiddle
我不太赞同“eval”选项。
var xxx = /abcd/; var yyy = /efgh/; var zzz = new RegExp(eval(xxx)+eval(yyy));
会给“// abcd // efgh //”这不是预期的结果。
使用像
var zzz = new RegExp(xxx.source+yyy.source);
会给“/ abcdefgh /”,这是正确的。
逻辑上没有必要评估,你知道你的expression。 你只需要它的来源或如何写它不必要的价值。 至于标志,你只需要使用RegExp的可选参数。
在我的情况下,我运行在^和$被用于几个expression式的问题,我试图连接在一起! 这些expression式是在程序中使用的语法filter。 现在我不想一起使用它们中的一些来处理PREPOSITIONS的情况。 我可能需要“切片”的来源,以删除开始和结束^(和/或)$ :)干杯,亚历克斯。
问题如果正则expression式包含像\ 1这样的后向匹配组。
var r = /(a|b)\1/ // Matches aa, bb but nothing else. var p = /(c|d)\1/ // Matches cc, dd but nothing else.
然后只是污染源将无法正常工作。 事实上,两者的结合是:
var rp = /(a|b)\1(c|d)\1/ rp.test("aadd") // Returns false
解决scheme:首先我们计算第一个正则expression式中匹配组的数量,然后对第二个中每个后向匹配的标记进行计数,然后按照匹配组的数量递增。
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' : '')); }
testing:
var rp = concatenate(r, p) // returns /(a|b)\1(c|d)\2/ rp.test("aadd") // Returns true
你将不得不使用新的RegExp! – )
使用2个参数的构造函数,并避免跟踪“/”的问题:
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
不,字面的方式不被支持。 你将不得不使用RegExp。
尽可能经常使用字面语法。 它更短,更清晰,你不需要逃避报价或双逃避反弹。 从“Javascript模式”,Stoyan Stefanov 2010。
但是使用New可能是连接的唯一方法。
我会避免评估。 它不安全。
提供了:
- 你知道你在你的正则expression式中做什么;
- 你有很多正则expression式组成一个模式,他们将使用相同的标志;
- 你发现它更容易分离你的小图案块成一个数组;
- 你也希望能够评论每个部分下一个开发或以后你自己;
- 你更喜欢直观地简化你的正则expression式,比如
/this/g
而不是new RegExp('this', 'g')
; - 你可以在一个额外的步骤中组装正则expression式,而不是从一开始就把它整合在一起。
那么你可能喜欢这样写:
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');
你可以这样做:
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>'; })
在我的特殊情况下(一个类似于代码镜像的编辑器),执行一个大的正则expression式要容易得多,而不是像下面那样用很多replace,因为每次我用一个html标签来replaceexpression式时,下一个模式将会难以在不影响html标签的情况下进行定位(并且不幸的是,在javascript中不支持这种良好的lookbehind ):
.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>')
你可以做这样的事情:
function concatRegex(...segments) { return new RegExp(segments.join('')); }
段是string(而不是正则expression式)作为单独的参数传入。
我更喜欢使用eval('your expression')
因为它不会在每个结尾添加/
='new RegExp'
。