更改RegExp标志 [英] Changing the RegExp flags
问题描述
所以基本上我自己编写了这个函数,以便能够计算字符串中子字符串的出现次数:
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;
};
方法本身表现相当好,基于RegExp和String的搜索与执行相当时间(在整个巨大的雷布拉德伯里的451华氏度中搜索所有the的时间约为2毫秒。
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实例的标志。在没有提供的正则表达式的全局标志设置为true的情况下调用此函数中的 String.prototype.match 是没有意义的,因为它只会记录第一次出现。你当然可以在传递给函数的每个RegExp上手动设置标志,但我更喜欢能够克隆然后操作提供的正则表达式的标志。
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.match in 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.prototype.global 标志(更准确地说是所有标志)似乎是只读的。从那里注释掉了第8行。
Astonishingly enough, I'm not permitted to do so as the RegExp.prototype.global flag (more precisely all flags) appear to be read-only. Thence the commented-out line 8.
所以我的问题是:是否有很好的方法来更改RegExp的标志对象?
So my question is: Is there a nice way of changing the flags of a RegExp object?
我真的不想做这样的事情:
I don't really wanna do stuff like this:
if(!expression.global)
expression = eval(expression.toString() + "g");
某些实现可能没有事件支持 RegExp.prototype.toString 而且只是从 Object.prototype 继承它,或者它可以完全不同的格式。它只是一个糟糕的编码实践开始。
Some implementations might not event support the RegExp.prototype.toString and 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.
推荐答案
首先,你的当前代码在<$时无法正常工作c $ c> needle 是一个不匹配的正则表达式。即以下行:
First, your current code does not work correctly when needle
is a regex which does not match. i.e. The following line:
return this.match(needle).length;
匹配
方法返回<$ c $当没有匹配时,c> null 。然后,当 null
的 length
属性(访问失败)时,会生成JavaScript错误。这很容易修复:
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:
var m = this.match(needle);
return m ? m.length : 0;
现在解决手头的问题。当你说 global
, ignoreCase
和 multiline
是只读属性。唯一的选择是创建一个新的RegExp。这很容易完成,因为正则表达式源字符串存储在 re.source
属性中。以下是您的函数的经过测试的修改版本,它纠正了上述问题并在 needle
尚未拥有 global $时创建一个新的RegExp对象c $ c>标志集:
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:
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;
};
这篇关于更改RegExp标志的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!