javascript 更改 RegExp 标志
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5835469/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Changing the RegExp flags
提问by Witiko
So basically I wrote myself this function so as to be able to count the number of occurances of a Substring in a String:
所以基本上我自己写了这个函数,以便能够计算字符串中子字符串的出现次数:
String.prototype.numberOf = function(needle) {
var num = 0,
lastIndex = 0;
if(typeof needle === "string" || needle instanceof String) {
while((lastIndex = this.indexOf(needle, lastIndex) + 1) > 0)
{num++;} return num;
} else if(needle instanceof RegExp) {
// needle.global = true;
return this.match(needle).length;
} return 0;
};
The method itself performs rather well and both the RegExp and String based searches are quite comparable as to the execution time (both ~2ms on the entire vast Ray Bradbury's "451 Fahrenheit" searching for all the "the"s).
该方法本身执行得相当好,并且基于 RegExp 和字符串的搜索在执行时间方面都非常相似(在整个 Ray Bradbury 的“451 Fahrenheit”搜索所有“the”的整个过程中均约为 2 毫秒)。
What sort of bothers me, though, is the impossibility of changing the flag of the supplied RegExp instance. There is no point in calling String.prototype.matchin this function without the global flag of the supplied Regular Expression set to true, as it would only note the first occurance then. You could certainly set the flag manually on each RegExp passed to the function, I'd however prefer being able to clone and then manipulate the supplied Regular Expression's flags.
然而,让我烦恼的是无法更改所提供的 RegExp 实例的标志。在没有将提供的正则表达式的全局标志设置为 true 的情况下,在此函数中调用String.prototype.match毫无意义,因为它只会记录第一次出现。您当然可以在传递给函数的每个 RegExp 上手动设置标志,但是我更喜欢能够克隆然后操作提供的正则表达式的标志。
Astonishingly enough, I'm not permitted to do so as the RegExp.prototype.globalflag (more precisely all flags) appear to be read-only. Thence the commented-out line 8.
令人惊讶的是,我不允许这样做,因为RegExp.prototype.global标志(更准确地说是所有标志)似乎是只读的。然后是注释掉的第 8 行。
So my question is: Is there a niceway of changing the flags of a RegExp object?
所以我的问题是:有没有一种改变 RegExp 对象标志的好方法?
I don't really wanna do stuff like this:
我真的不想做这样的事情:
if(!expression.global)
expression = eval(expression.toString() + "g");
Some implementations might not event support the RegExp.prototype.toStringand simply inherit it from the Object.prototype, or it could be a different formatting entirely. And it just seems as a bad coding practice to begin with.
一些实现可能不支持RegExp.prototype.toString而只是从Object.prototype继承它,或者它可能是完全不同的格式。这似乎是一种糟糕的编码习惯。
采纳答案by ridgerunner
First, your current code does not work correctly when needle
is a regex which does not match. i.e. The following line:
首先,当needle
正则表达式不匹配时,您当前的代码无法正常工作。即以下行:
return this.match(needle).length;
The match
method returns null
when there is no match. A JavaScript error is then generated when the length
property of null
is (unsuccessfully) accessed. This is easily fixed like so:
当没有匹配时,该match
方法返回null
。当(不成功)访问的length
属性时,null
会生成 JavaScript 错误。这很容易修复,如下所示:
var m = this.match(needle);
return m ? m.length : 0;
Now to the problem at hand. You are correct when you say that global
, ignoreCase
and multiline
are read only properties. The only option is to create a new RegExp. This is easily done since the regex source string is stored in the re.source
property. Here is a tested modified version of your function which corrects the problem above and creates a new RegExp object when needle
does not already have its global
flag set:
现在到手头的问题。你说的是对的global
,ignoreCase
并且multiline
是只读属性。唯一的选择是创建一个新的 RegExp。这很容易完成,因为正则表达式源字符串存储在re.source
属性中。这是您的函数的经过测试的修改版本,它更正了上述问题,并在needle
尚未global
设置其标志时创建一个新的 RegExp 对象:
String.prototype.numberOf = function(needle) {
var num = 0,
lastIndex = 0;
if (typeof needle === "string" || needle instanceof String) {
while((lastIndex = this.indexOf(needle, lastIndex) + 1) > 0)
{num++;} return num;
} else if(needle instanceof RegExp) {
if (!needle.global) {
// If global flag not set, create new one.
var flags = "g";
if (needle.ignoreCase) flags += "i";
if (needle.multiline) flags += "m";
needle = RegExp(needle.source, flags);
}
var m = this.match(needle);
return m ? m.length : 0;
}
return 0;
};
回答by David Ruttka
回答by ChaosPandion
There isn't much you can do but I highly recommend you avoid using eval
. You can extend the RegExp prototype to help you out.
您无能为力,但我强烈建议您避免使用eval
. 您可以扩展 RegExp 原型来帮助您。
RegExp.prototype.flags = function () {
return (this.ignoreCase ? "i" : "")
+ (this.multiline ? "m" : "")
+ (this.global ? "g" : "");
};
var reg1 = /AAA/i;
var reg2 = new RegExp(reg1.source, reg1.flags() + 'g');
回答by kevin cline
r = new Regexp(r.source, r.flags + (r.global ? "" : "g"));