更改RegExp标志 [英] Changing the RegExp flags

查看:70
本文介绍了更改RegExp标志的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以基本上我自己编写了这个函数,以便能够计算字符串中子字符串的出现次数:

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 标志集:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆