更改RegExp标志

Wit*_*iko 15 javascript regex flags prototype

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

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;
};
Run Code Online (Sandbox Code Playgroud)

该方法本身表现相当不错,基于RegExp和基于字符串的搜索与执行时间相当(在整个庞大的Ray Bradbury的"451 Fahrenheit"上搜索所有"the"的两个~2ms).

但是,令我感到困扰的是,无法更改提供的RegExp实例的标志.在没有提供的正则表达式的全局标志设置为true的情况下调用此函数中的String.prototype.match是没有意义的,因为它只会记录第一次出现.你当然可以在传递给函数的每个RegExp上手动设置标志,但我更喜欢能够克隆然后操作提供的正则表达式的标志.

令人惊讶的是,我不允许这样做,因为RegExp.prototype.global标志(更确切地说是所有标志)似乎是只读的.从那里评论出来的第8行.

所以我的问题是:有没有一种很好的方法来更改RegExp对象的标志?

我真的不想做这样的事情:

if(!expression.global)
  expression = eval(expression.toString() + "g");
Run Code Online (Sandbox Code Playgroud)

某些实现可能不支持RegExp.prototype.toString事件,只是从Object.prototype继承它,或者它可能完全是不同的格式.而这似乎是一个糟糕的编码实践开始.

rid*_*ner 14

首先,当needle正则表达式不匹配时,您当前的代码无法正常工作.即以下行:

return this.match(needle).length;
Run Code Online (Sandbox Code Playgroud)

当没有匹配时,该match方法返回null.然后,当(未成功)访问length属性时会生成JavaScript错误null.这很容易修复如下:

var m = this.match(needle);
return m ? m.length : 0;
Run Code Online (Sandbox Code Playgroud)

现在到手头的问题.当你这么说时你是对的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;
};
Run Code Online (Sandbox Code Playgroud)


Dav*_*tka 8

var globalRegex = new RegExp(needle.source, "g");
Run Code Online (Sandbox Code Playgroud)

现场演示 编辑:m只是为了证明你可以设置多个修饰符

var regex = /find/;
var other = new RegExp(regex.source, "gm");
alert(other.global);
alert(other.multiline);
Run Code Online (Sandbox Code Playgroud)


kev*_*ine 6

r = new Regexp(r.source, r.flags + (r.global ? "" : "g"));
Run Code Online (Sandbox Code Playgroud)